/commands/npm/npm-explain-why-package-installed
npm explain / npm ls PACKAGE: why is this package installed?
- tool
- npm
- versions
- npm 7+ (npm explain), npm ls: all versions
- os
- any
npm explain PACKAGE (alias npm why) prints every dependency path that caused PACKAGE to be installed, from the package up to your project, with the version range each parent requested. npm ls PACKAGE shows the same information as a tree from the root down. Use them to find out which direct dependency brings in a transitive package, for example before fixing a vulnerability report.
Example
The project depends only on chalk; color-name arrives through three levels of dependencies:
npm init -y >/dev/null
npm install --silent --no-audit --no-fund chalk@4.1.2 >/dev/null 2>&1
echo "--- npm explain color-name"
npm explain color-name
echo "--- npm ls color-name"
npm ls color-name | tail -n +2Output
--- npm explain color-name
color-name@1.1.4
node_modules/color-name
color-name@"~1.1.4" from color-convert@2.0.1
node_modules/color-convert
color-convert@"^2.0.1" from ansi-styles@4.3.0
node_modules/ansi-styles
ansi-styles@"^4.1.0" from chalk@4.1.2
node_modules/chalk
chalk@"^4.1.2" from the root project
--- npm ls color-name
└─┬ chalk@4.1.2
└─┬ ansi-styles@4.3.0
└─┬ color-convert@2.0.1
└── color-name@1.1.4Read npm explain from top to bottom: color-name@1.1.4 is needed by color-convert@2.0.1 (which asked for ~1.1.4), which is needed by ansi-styles, which is needed by chalk, which the root project requires. On Windows npm ls draws the tree with ASCII characters as shown; on Linux and macOS it uses line-drawing characters.
Useful variants
| Command | Shows |
|---|---|
| npm explain PKG | All paths that require PKG, bottom-up, with requested ranges |
| npm ls PKG | Tree paths from the root to every installed copy of PKG |
| npm ls PKG --all | Same, including deeper levels (npm ls without a name stops at depth 0) |
| npm ls --all | The whole dependency tree |
| npm ls PKG --json | Machine-readable tree |
| npm explain node_modules/a/node_modules/PKG | Explain one specific nested copy |
Fixing what you find
- Upgrade the direct dependency at the top of the chain, so it pulls a newer transitive version.
- Or force a version of the transitive package with
overridesinpackage.json(npm 8.3+):
{
"overrides": {
"color-name": "1.1.4"
}
}