Symlinked `node_modules` structure
This article only describes how pnpm’s are structured when there are no packages with peer dependencies. For the more complex scenario of dependencies with peers, see how peers are resolved.
pnpm’s node_modules
layout uses symbolic links to create a nested structure of dependencies.
Every file of every package inside node_modules
is a hard link to the content-addressable store. Let’s say you install foo@1.0.0
that depends on bar@1.0.0
. pnpm will hard link both packages to node_modules
like this:
As you might have noticed, both packages are hard linked into a subfolder inside a node_modules
folder (foo@1.0.0/node_modules/foo
). This is needed to:
The next stage of installation is symlinking dependencies. bar
is going to be symlinked to the foo@1.0.0/node_modules
folder:
Next, direct dependencies are handled. foo
is going to be symlinked into the root node_modules
folder because foo
is a dependency of the project:
Let’s add qar@2.0.0
as a dependency of bar
and . This is how the new structure will look:
As you may see, even though the graph is deeper now (foo > bar > qar
), the directory depth in the file system is still the same.
This layout might look weird at first glance, but it is completely compatible with Node’s module resolution algorithm! When resolving modules, Node ignores symlinks, so when bar
is required from foo@1.0.0/node_modules/foo/index.js
, Node does not use bar
at foo@1.0.0/node_modules/bar
, but instead, bar
is resolved to its real location (bar@1.0.0/node_modules/bar
). As a consequence, bar
can also resolve its dependencies which are in bar@1.0.0/node_modules
.