One of the very great features of pnpm is that in one project, a specific version of a package will always have one set of dependencies. There is one exclusion from it though - packages with peer dependencies.
Peer dependencies are resolved from dependencies installed higher in the dependency graph.
That means if
firstname.lastname@example.org has two peers (
baz@^1) then it might have different sets of dependencies
in the same project.
- foo-parent-1 - email@example.com - firstname.lastname@example.org - email@example.com - foo-parent-2 - firstname.lastname@example.org - email@example.com - firstname.lastname@example.org
In the example above,
email@example.com is installed for
foo-parent-2. Both packages have
bazas well, but
they depend on different versions of
baz. As a result,
firstname.lastname@example.org has two different sets of dependencies: one with
and the other one with
email@example.com. In order to support these use cases, pnpm has to hard link
firstname.lastname@example.org as many times as many different dependency sets it has.
Normally, if a package does not have peer dependencies, it is hard linked to a
node_modules folder next to symlinks of its dependencies.
foo has peer dependencies, there cannot be one single set of dependencies for it, so
we create different sets, for different peer dependency resolutions:
We create symlinks either to the
foo that is inside
email@example.comfirstname.lastname@example.org/node_modules or to the one in
As a consequence, the Node.js module resolver algorithm will find the correct peers.
If the resolved peer is a direct dependency of the project, it is not grouped separately with the dependent package.
This is done to make it easier to make predictable and fast named (
pnpm i foo) and general (
pnpm i) installations.
So if the project dependends on
email@example.com, the dependencies from our example will be grouped like this:
If a package has no peer dependencies but has dependencies with peers that are resolved higher in the graph, then
that transitive package can appear in the project with different sets of dependencies. For instance, there's package
with a single dependency
firstname.lastname@example.org has a peer dependency
email@example.com will never resolve the
firstname.lastname@example.org, so it becomes dependent from the peers of
email@example.com as well.
Here's how it will look like in
node_modules/.registry.npmjs.org, in case if
firstname.lastname@example.org will need to appear twice in the project's
node_modules, once resolved with
email@example.com and once with