全球虚拟商店
默认情况下,pnpm 会在每个项目的 node_modules 内创建一个 .pnpm 目录——这就是“虚拟存储”。它包含指向 基于内容寻址的存储 中文件的硬链接。每个项目都有自己的虚拟存储投影——pnpm 会将基于内容寻址存储中的文件硬链接到 .pnpm 目录结构中。实际的文件内容在磁盘上只存在一次,但目录结构会为每个项目重新创建,以便 Node.js 的模块解析算法能够为每个包找到正确的依赖。
🌐 By default, pnpm creates a .pnpm directory inside each project's node_modules — this is the "virtual store". It contains hardlinks to files in the content-addressable store. Every project gets its own projection of this virtual store — pnpm hardlinks files from the content-addressable store into the .pnpm directory structure. The actual file contents exist only once on disk, but the directory structure is recreated for each project so that Node.js's module resolution algorithm can find the right dependencies for each package.
全球虚拟存储(enableGlobalVirtualStore: true)改变了这一点。每个项目不再拥有自己的 node_modules/.pnpm 目录,pnpm 维护一个单独的共享虚拟存储(位于 <store-path>/links/,运行 pnpm store path 可找到 <store-path>)。每个项目的 node_modules 仅包含指向此共享位置的符号链接。
🌐 The global virtual store (enableGlobalVirtualStore: true) changes this. Instead of each project having its own node_modules/.pnpm directory, pnpm maintains a single shared virtual store (located at <store-path>/links/, run pnpm store path to find <store-path>). Each project's node_modules contains only symlinks pointing into this shared location.
默认行为 vs 全局虚拟商店
🌐 Default behavior vs global virtual store
默认(每项目虚拟商店)
🌐 Default (per-project virtual store)
project-a/
└── node_modules/
├── lodash → .pnpm/lodash@4.17.21/node_modules/lodash
└── .pnpm/
└── lodash@4.17.21/
└── node_modules/
└── lodash/ ← hardlinks to content-addressable store
project-b/
└── node_modules/
├── lodash → .pnpm/lodash@4.17.21/node_modules/lodash
└── .pnpm/
└── lodash@4.17.21/
└── node_modules/
└── lodash/ ← same hardlinks, duplicated directory structure
每个项目都有其自己的 .pnpm,带有硬链接。文件内容不会在磁盘上重复(硬链接共享 inode),但目录结构是独立的。在大型单体仓库或许多并行检出情况下,在 pnpm install 期间创建数千个硬链接所花费的时间会累积起来。
🌐 Each project has its own .pnpm with hardlinks. The file contents aren't duplicated on disk (hardlinks share inodes), but the directory structure is. With large monorepos or many parallel checkouts, the time spent creating thousands of hardlinks during pnpm install adds up.
拥有全球虚拟商店
🌐 With global virtual store
project-a/
└── node_modules/
└── lodash → <global-store>/links/@/lodash/4.17.21/<hash>/node_modules/lodash
project-b/
└── node_modules/
└── lodash → <global-store>/links/@/lodash/4.17.21/<hash>/node_modules/lodash ← same target
两个项目都直接符号链接到全局虚拟存储的同一位置。没有每个项目的 .pnpm 目录。全局虚拟存储本身包含指向内容可寻址存储的硬链接——但这只会在每个依赖图中发生一次(下面会详细说明),而不是每个项目一次。
🌐 Both projects symlink directly to the same location in the global virtual store. There's no per-project .pnpm directory. The global virtual store itself contains the hardlinks to the content-addressable store — but that happens only once per dependency graph (more on that below), not per project.
软件包身份是如何工作的
🌐 How package identity works
在全球虚拟存储中,每个包目录都是用其依赖图的哈希命名的。两个使用 lodash@4.17.21 并且具有相同传递依赖树的项目将指向完全相同的目录。如果依赖树不同(例如,不同的同级依赖),pnpm 会创建单独的条目。这在概念上类似于 NixOS 使用依赖图哈希管理包 的方式。
🌐 In the global virtual store, each package directory is named by the hash of its dependency graph. Two projects that use lodash@4.17.21 with the same transitive dependency tree will point to the exact same directory. If the dependency trees differ (e.g., different peer dependencies), pnpm creates separate entries. This is conceptually similar to how NixOS manages packages using dependency graph hashes.
何时使用它
🌐 When to use it
当你在磁盘上有同一项目的多个签出时,全球虚拟存储最有用——例如,在使用 git worktrees 进行多代理开发 时。在这种情况下,每个工作树几乎可以免费获得一个 node_modules,因为所有实际的软件包内容已经存在于共享存储中。
🌐 The global virtual store is most useful when you have multiple checkouts of the same project on disk — for example, when using git worktrees for multi-agent development. In that scenario, each worktree gets a nearly free node_modules because all the real package content already exists in the shared store.
它还加快了同一台机器上不相关项目的安装速度,因为任何已被任何项目安装的包版本都可以立即使用。
🌐 It also speeds up installations across unrelated projects on the same machine, since any package version that's already been installed by any project is available instantly.
限制
🌐 Limitations
-
CI environments: In CI, caches are typically absent, so there's no warm global store to benefit from. The global virtual store is generally not useful in CI.
-
Shared trust domain: The global virtual store and the content-addressable store are shared writable state. Use them only for projects, users, and jobs that trust each other, and protect the store path with filesystem permissions.
-
ESM hoisting: pnpm uses the
NODE_PATHenvironment variable to support hoisted dependencies with the global virtual store. However, Node.js does not respectNODE_PATHfor ESM imports. If ESM dependencies try to import packages not declared in their ownpackage.json, resolution will fail. You can work around this with packageExtensions or the @pnpm/plugin-esm-node-path config dependency.
全局虚拟存储目前默认对项目安装禁用,并被标记为实验性,因为某些工具可能无法正确处理符号链接的 node_modules。你需要在 pnpm-workspace.yaml 中显式设置 enableGlobalVirtualStore: true 才能将其用于项目安装。在 pnpm v11 中,全局虚拟存储默认对通过 pnpm dlx(pnpx) 安装的包以及全局安装的包启用。未来版本的目标是默认对所有安装启用它。
🌐 The global virtual store is currently disabled by default for project installs and marked as experimental, as some tools may not work correctly with symlinked node_modules. You need to explicitly set enableGlobalVirtualStore: true in pnpm-workspace.yaml to use it for project installs. In pnpm v11, the global virtual store is enabled by default for packages installed via pnpm dlx (pnpx) and globally installed packages. The goal is to enable it by default for all installations in a future version.
全局包
🌐 Global packages
在 pnpm v11 中,全局安装(pnpm add -g)和 pnpm dlx 默认使用全局虚拟存储。有关 v11 中全局包管理的完整指南,包括独立安装和新的二进制文件位置,请参阅 全局包。
🌐 In pnpm v11, global installs (pnpm add -g) and pnpm dlx use the global virtual store by default. See Global Packages for the full guide on how global package management works in v11, including isolated installations and the new binaries location.
配置
🌐 Configuration
查看 enableGlobalVirtualStore 设置参考以获取所有配置详情。
🌐 See the enableGlobalVirtualStore setting reference for all configuration details.