This article only describes how pnpm's
node_modulesare structured when there are no packages with peer dependencies. For the more complex scenario of dependencies with peers, see how peers are resolved.
node_modules layout uses symbolic links to create a nested structure of dependencies.
[email protected] is linked to
node_modules from the global store only once.
Let's say you install
[email protected] that depends on
[email protected]. pnpm will hard link both packages to
node_modules like this:
These are the only "real files" in
node_modules. Once all the packages are hard linked to
node_modules, symlinks are
created to build the nested dependency graph structure.
As you might have noticed, both packages are hard linked into a subfolder inside a
node_modules folder (
This is needed to:
- allow packages to require themselves.
fooshould be able to do
- avoid circular symlinks. Dependencies of packages are placed in the same folder in which the dependent packages are.
For Node.js it doesn't make a difference whether dependencies are inside the package's
node_modulesor in any other
node_modulesin the parent directories.
The next stage of installation is symlinking dependencies.
bar is going to be symlinked to the
foo is going to be symlinked to the root
node_modules folder because
foo is a dependency of the project:
This is a very simple example. However, the layout will stay flat in the file system regardless of the number of dependencies and the depth of the dependency graph.
[email protected] as a dependency of
foo. This is how the
node_modules will look like:
As you can see, even though the depth of the graph is bigger (
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 Node.js-compatible! When resolving modules, Node.js ignores symlinks.
bar is required from
foo/1.0.0/node_modules/foo/index.js, Node.js is not using
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
A great bonus of this layout is that only packages that are really in the dependencies are accessible. With flattened
node_modules, all hoisted
packages are accessible. To read more about why this is an advantage, see pnpm's strictness helps to avoid silly bugs.