In Composer, how do composer why and composer why-not help when an upgrade to a new major version is blocked?
answer
- why = depends, why-not = prohibits
- who requires this package
- who blocks this version
- -t prints a tree
- works for php versions too
basics
~20 scomposer why vendor/pkg (alias of depends) lists the installed packages that require it and their constraints. composer why-not vendor/pkg 3.0 (alias of prohibits) lists what blocks that version, and works for php too. -t shows a tree.
solid answer
~40 sWhen `composer require vendor/pkg:^3.0` fails, the solver's error explains the conflict, but on a large graph it is long. Two commands answer the targeted questions. `composer why vendor/pkg` (alias of `depends`) lists every installed package that requires `vendor/pkg`, with the constraint it uses; `-r` or `-t` follows the chain up to your root, and `require-dev` links count only for the root. `composer why-not vendor/pkg 3.0` (alias of `prohibits`) lists the packages whose constraints or conflicts stop 3.0 from being installed, recursively with `-t`. It also works on platform packages: `composer why-not php 8.5` shows what blocks a PHP upgrade. The output tells you which dependency must be upgraded first, which one to replace, or whether to wait, and then `composer update` with `-W` moves the whole chain in one go.
code
bash · 4 linescomposer why acme/http -t
composer why-not acme/http 3.0 -t
composer why-not php 8.5
composer require acme/http:^3.0 -W --dry-rungo deeper
Know that composer why tells you which package pulled another one in.
Use why-not with a version to find blockers, and -t to see the chain up to your root.
Turn why-not output into an upgrade plan: update blockers together with -W, widen your own constraints, or replace abandoned packages.
Use why-not php across services to size a runtime upgrade programme and decide which dependencies to replace before committing to a date.
## The situation You want the next major of a package, say `acme/http` 3.0. `composer require acme/http:^3.0 -W` fails with "Your requirements could not be resolved to an installable set of packages", followed by a problem report. On a small project the report is readable. On a project with a few hundred packages it can run to dozens of lines, and what you really need is a short answer to two questions: **who uses this package**, and **who stops this version**. ## `composer why` (alias of `depends`) `composer why vendor/package` lists every installed package that depends on it, with the constraint each one declares: ```text acme/api-client 2.4.0 requires acme/http (^2.1) acme/webhooks 1.9.3 requires acme/http (^2.0) ``` - `-r` (`--recursive`) resolves each line upward until it reaches the root package. - `-t` (`--tree`) prints the same as a nested tree and implies `-r`. - An optional version constraint limits the search. - As during installation, `require-dev` links count only for the root package. It also answers "why is this package even installed?", useful for a surprise transitive dependency or after a messy merge. ## `composer why-not` (alias of `prohibits`) `composer why-not vendor/package 3.0` asks the inverse: if I wanted this version, which packages would object? It lists each package whose `require` constraint excludes that version, or whose `conflict` entry names it: ```text acme/api-client 2.4.0 requires acme/http (^2.1) acme/webhooks 1.9.3 requires acme/http (^2.0) ``` `-r` and `-t` work the same way, following each blocker back to the root, so you see whether the blocker is something you require directly or something three levels down. ## Platform packages count too Both commands accept platform packages. `composer why-not php 8.5` lists every installed package whose `php` requirement excludes PHP 8.5, which is the first thing to run before planning a runtime upgrade. ## Turning the output into a plan For each blocker that `why-not` lists: 1. **Does a newer release of the blocker accept the new version?** Then update both together: `composer update acme/api-client acme/http -W`, or `composer require acme/http:^3.0 -W`, which lets the solver move the chain. 2. **Is the blocker abandoned or slow to move?** Consider replacing it, or wait. 3. **Is it a root requirement of yours with a narrow constraint?** Widen your own constraint in `composer.json`; `why-not` often shows that the blocker was you. | Question | Command | |---|---| | Who requires `acme/http`? | `composer why acme/http` | | Full chain to my root? | `composer why acme/http -t` | | What blocks `acme/http` 3.0? | `composer why-not acme/http 3.0` | | What blocks PHP 8.5? | `composer why-not php 8.5` | ## A worked example Suppose `composer why-not acme/http 3.0 -t` prints a tree in which `acme/webhooks` 1.9.3 requires `acme/http ^2.0`, and `acme/webhooks` is required by your root. You then check whether `acme/webhooks` has a release that accepts 3.0. If 2.0 does, the plan is one command, `composer require acme/webhooks:^2.0 acme/http:^3.0 -W`, followed by the tests, because both majors move together. If no such release exists, the upgrade waits, or `acme/webhooks` is replaced. Either way, you learn it in a minute instead of by reading a long solver report line by line. ## What these commands do not do They read the **installed** packages and their declared constraints (for `why-not`, Composer also loads the requested version's own metadata from your repositories, so conflicts it declares against installed packages show up). They do not run the solver across every available version of the blockers. A blocker's newer release may already support 3.0, and `why-not` will not say so. To learn that, look at the blocker's newer releases, for example with `composer show acme/api-client --all`, which lists its available versions, or try the update with `--dry-run`.
- composer why-not lists a package you require directly. What is the likeliest fix?Your own constraint, or the constraint of that direct dependency, is too narrow. Check whether a newer release of the direct dependency accepts the target version; if so, update both together with `-W`. If the blocker is your own `composer.json` constraint, widen it in the same change.
- Before upgrading production from PHP 8.3 to 8.5, which Composer command shows what will break at dependency level?`composer why-not php 8.5` lists every installed package whose `php` requirement excludes 8.5. Each line is a dependency that needs a newer release, or replacing, before the upgrade; it does not test your own code, which still needs its test suite run on the new PHP.
why is asking the office 'who is still using the old printer?'; why-not is asking 'who objects if we replace it?' Neither buys the new printer; they tell you whom to talk to first.
saying these in an interview costs you the question
- composer why-not installs the target version if nothing blocks it
- composer why shows the packages that vendor/package itself requires
- why-not only works for regular packages, not for php
- why-not proves no newer release of the blocker supports the target version
- The solver's error message is the only way to find a blocking package