yarn why PACKAGE: find out why a package is installed
- tool
- Yarn
- versions
- Yarn 1.22, Yarn 4.x
- os
- any
yarn why PACKAGE explains why a package is in your dependency tree: it lists the packages that depend on it and the version that was resolved. Use it to find who pulls in a vulnerable or duplicated package before upgrading or adding a resolutions entry. It works in Yarn 1 and Yarn 2+, with different output formats.
Yarn 1
cat > package.json <<'EOF'
{ "name": "app", "version": "1.0.0", "license": "MIT", "dependencies": { "is-odd": "3.0.1" } }
EOF
npx --yes yarn@1 install --silent --no-progress > /dev/null 2>&1
npx --yes yarn@1 why is-number | grep -vE "Disk size|Number of shared|^Done in"Output
yarn why v1.22.22 [1/4] Why do we have the module "is-number"...? [2/4] Initialising dependency graph... [3/4] Finding dependency... [4/4] Calculating file sizes... info => Found "is-number@6.0.0" info Reasons this module exists - "is-odd" depends on it - Hoisted from "is-odd#is-number"
is-number is not in package.json; it is installed because is-odd depends on it, and Yarn 1 hoisted it to the top of node_modules.
Yarn 4
cat > package.json <<'EOF'
{ "name": "app", "version": "1.0.0", "license": "MIT", "dependencies": { "is-odd": "3.0.1" } }
EOF
touch yarn.lock
npx --yes @yarnpkg/cli-dist@4 install > /dev/null 2>&1
npx --yes @yarnpkg/cli-dist@4 why is-numberOutput
└─ is-odd@npm:3.0.1 └─ is-number@npm:6.0.0 (via npm:^6.0.0)
Yarn 4 prints a tree: the top line is the direct dependency, below it the package you asked about, with the range that requested it (via npm:^6.0.0). Add -R (--recursive) to show the full chain from your workspace, and --peers to include peer dependencies.
cat > package.json <<'EOF'
{ "name": "app", "version": "1.0.0", "license": "MIT", "dependencies": { "is-odd": "3.0.1" } }
EOF
touch yarn.lock
npx --yes @yarnpkg/cli-dist@4 install > /dev/null 2>&1
echo "--- why is-number -R"
npx --yes @yarnpkg/cli-dist@4 why is-number -R
echo "--- why left-pad (not installed)"
npx --yes @yarnpkg/cli-dist@4 why left-pad
echo "exit=$?"Output
--- why is-number -R
└─ app@workspace:.
└─ is-odd@npm:3.0.1 (via npm:3.0.1)
└─ is-number@npm:6.0.0 (via npm:^6.0.0)
--- why left-pad (not installed)
exit=0With -R the chain starts at the workspace itself (app@workspace:.). A package that is not installed produces no output and exit code 0.
Equivalents in other package managers
| Tool | Command |
|---|---|
| Yarn 1 / Yarn 4 | yarn why PACKAGE |
| npm | npm explain PACKAGE (alias npm why) |
| pnpm | pnpm why PACKAGE |
| Bun | bun why PACKAGE |
To force a single version once you know who requests it, add a resolutions field to package.json (Yarn) or overrides (npm, pnpm), then run yarn install again.
When to use it
- A security advisory names a package you never added.
yarn whyshows which direct dependency brings it in, so you know what to upgrade. - Several versions of the same package are installed. Yarn 4 lists one entry per resolved version, with the range each dependent asked for; the ranges explain why they could not be merged.
- A package seems unnecessary. If the only reason is a dependency you no longer use, removing that dependency removes both.
- Before adding a resolution. Forcing a version with
resolutionsis safe only if every dependent's range accepts it;yarn whyshows those ranges.
Reading the output
| Part | Meaning |
|---|---|
| is-odd@npm:3.0.1 | A package that depends on the one you asked about, with its resolved version |
| (via npm:^6.0.0) | The range that package requested; several dependents can request different ranges |
| app@workspace:. | Your own workspace, shown at the top with -R |
| Hoisted from (Yarn 1) | Yarn 1 moved the package up to the top of node_modules from the named parent |
| No output (Yarn 2+) | The package is not installed at all |
FAQ
Why does yarn why print nothing?
The package is not in the dependency tree. Yarn 4 prints no output in that case and exits 0; Yarn 1 prints error We couldn't find a match! but also exits 0, so check the output, not the exit code, in scripts.
How do I see the whole chain from my project to a deep dependency?
In Yarn 2+ add -R (--recursive): the tree then starts at your workspace and shows every package on the path. Yarn 1 lists the direct reasons and the hoisting information instead.
Can I get yarn why output as JSON?
Yes, in Yarn 2+ with --json, which prints a JSON object for each dependent with the descriptor that requested the package.