Run composer why vendor/package to list which installed packages depend on it, and add the recursive or tree option to follow the chain up to your own composer.json. If an upgrade is blocked, composer why-not vendor/package version tells you which packages stand in the way.
What the commands do
The Composer CLI documentation says why is an alias of depends, which tells you which other packages depend on a certain package. The recursive option resolves up to the root package, and the tree option prints a nested tree and implies recursive. The why-not command is an alias of prohibits, which lists the packages blocking a given package from being installed. It accepts a version constraint, and platform requirements too, such as php 8.
Worked example in steps
Suppose an advisory names a transitive package you never chose.
- Confirm the locked version with a quick look at composer.lock.
- Run
whywith the tree option to see the path. - Identify the direct requirement you control, near the top of the tree.
- Check whether a newer version of that direct package allows the fixed version.
- If not, run
why-notwith the fixed version to see what blocks it.
composer why vendor/vulnerable --tree
composer why-not vendor/vulnerable 2.5.1
composer update vendor/direct --with-dependencies
Reading the answers
| You see | It means | Next move |
|---|---|---|
| Your root requires it | Direct dependency | Update your own constraint |
| One direct package requires it | Transitive via that package | Update that package |
| why-not names a package with a tight constraint | That package holds the old version | Upgrade it, replace it, or ask the maintainer |
| why-not names php | The fix needs a newer PHP | Plan a runtime upgrade |
When nothing can move
Sometimes the fix needs a major upgrade of a direct package. Then you have choices: upgrade the direct package, replace it, or accept the risk with a written reason and a review date.
Why tracing matters
Teams often patch the wrong thing because they see only the package name in the advisory. The tree view shows who owns the decision. It also shows how many parts of your system share that dependency, which tells you how big the change will be.
Try it yourself
Click through it at your own pace, or open it full screen. Trace one transitive package back to the direct requirement that brought it in.
Where Safeguard fits
Safeguard's policies and gates can check dependency changes in a pull request before merge. A free scan shows what it finds today.
Quick check
Is why the same as depends?
Yes. The documentation lists why as an alias of depends, and why-not as an alias of prohibits.
Does why show dev dependencies?
It reports on installed packages. If you installed require-dev packages, they can appear in the results.
Sources
Last reviewed: 19 October 2026.