Skip to content

/commands/pnpm/pnpm-why

pnpm why package: find out why a dependency is installed

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
pnpm
versions
pnpm 8+, pnpm 9
os
any

pnpm why is-number shows every path in the dependency graph that leads to is-number: which direct dependency of your project pulls it in and through which intermediate packages, with the installed versions. Use it to find where an unexpected or vulnerable package comes from before you update or override it. It reads the installed graph, so run pnpm install first.

Example

bash
echo '{ "name": "app", "version": "1.0.0", "private": true }' > package.json
P="npx --yes pnpm@9"
$P add --silent is-odd@3.0.1 is-even@1.0.0
$P why is-number

Output

Legend: production dependency, optional only, dev only

app@1.0.0 /tmp/work (PRIVATE)

dependencies:
is-even 1.0.0
└─┬ is-odd 0.1.2
  └── is-number 3.0.0
is-odd 3.0.1
└── is-number 6.0.0

is-number is not a direct dependency: it is installed twice, in two versions, because is-odd@3.0.1 asks for one version and is-even (through is-odd@0.1.2) asks for another. pnpm prints the tree from your direct dependencies down to the package, grouped by dependency type (dependencies, devDependencies). The example runs pnpm through npx pnpm@9; with pnpm installed the command is pnpm why is-number.

Options

CommandWhat it does
pnpm why lodashPaths to lodash in the current project
pnpm why -r lodashEvery package of the workspace
pnpm why 'babel-*'Every package matching a pattern
pnpm why lodash --prod / --devOnly production or only dev dependencies
pnpm why lodash --depth 1Limit how deep the tree is printed
pnpm why lodash --jsonMachine-readable output
pnpm list --depth InfinityThe whole installed tree instead of the paths to one package

What to do with the answer

  • Two versions of one package, as above, are normal when ranges do not overlap. To force one version everywhere, add it to pnpm.overrides in package.json and run pnpm install; test afterwards, because the package that asked for the other version may break.
  • A vulnerable transitive package: update the direct dependency at the top of the chain first (pnpm update -L name, see pnpm update --latest); use an override only if no fixed version of the parent exists.
  • A package you did not expect at all usually comes from an optional or peer dependency of something else; the chain shows which one.

Pitfalls

  • pnpm why reads node_modules and the lockfile of the current project. In a workspace, a package installed for another package is only shown with -r or from that package's folder.
  • Peer dependencies are listed under the package that resolves them, so the same version can appear in several chains.
  • Other package managers have the same command with different output: npm explain and yarn why.

How to confirm it worked

After an override or an update, run pnpm why package again: the chains should show only the version you want. pnpm list package --depth Infinity gives the same information as a flat tree.

FAQ

How do I see why a package is installed in every workspace package?

Run pnpm why -r package from the workspace root. Without -r, pnpm why only looks at the package in the current folder.

Why does pnpm why print nothing?

The package is not in the dependency graph of the current project: it is not installed, it was removed, or it belongs to another workspace package. Check the name, run pnpm install, or add -r.

How do I get the result as JSON?

Add --json, for example pnpm why lodash --json. It prints the same chains as structured data that scripts can read.

Sources