Skip to content

/commands/yarn/yarn-why

yarn why PACKAGE: find out why a package is installed

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
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

bash
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

bash
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-number

Output

└─ 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.

bash
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=0

With -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

ToolCommand
Yarn 1 / Yarn 4yarn why PACKAGE
npmnpm explain PACKAGE (alias npm why)
pnpmpnpm why PACKAGE
Bunbun 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 why shows 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 resolutions is safe only if every dependent's range accepts it; yarn why shows those ranges.

Reading the output

PartMeaning
is-odd@npm:3.0.1A 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.

Sources