Skip to main content

pnpm 11.0

· 15 min read
Zoltan Kochan
Lead maintainer of pnpm

pnpm 11 来了!此版本加强了在 v10 版本周期中引入的安全默认设置,取消了用于发布的 npm CLI 回退,转而使用原生实现,使用单个 SQLite 数据库替换了每个包的 JSON 存储索引,并隔离了全局安装,使它们不再相互干扰。

🌐 pnpm 11 is here! This release tightens the security defaults introduced throughout the v10 cycle, drops the npm CLI fallback for publishing in favor of a native implementation, replaces the JSON-per-package store index with a single SQLite database, and isolates global installs so they no longer interfere with each other.

它还需要 Node.js 22 或更高版本——pnpm 本身现在是纯 ESM。

🌐 It also requires Node.js 22 or newer — pnpm itself is now pure ESM.

从 v10 升级?请参阅 从 v10 迁移到 v11 指南。大多数配置更改是机械性的,可以通过 pnpm-v10-to-v11 codemod 应用。

🌐 Upgrading from v10? See the Migrating from v10 to v11 guide. Most config changes are mechanical and can be applied by the pnpm-v10-to-v11 codemod.

亮点

🌐 Highlights

  • Node.js 22+ required. Support for Node 18, 19, 20, and 21 is dropped. The standalone executable requires glibc 2.27 or newer.

  • Supply-chain protection on by default. minimumReleaseAge defaults to 1440 (1 day) and blockExoticSubdeps defaults to true.

  • allowBuilds replaces the legacy build-dependency settings. onlyBuiltDependencies, onlyBuiltDependenciesFile, neverBuiltDependencies, ignoredBuiltDependencies, and ignoreDepScripts are gone.

  • Global installs are isolated and use the global virtual store by default. Each pnpm add -g gets its own directory with its own package.json, node_modules, and lockfile.

  • New SQLite-backed store index (store v11), with bundled manifests and hex digests for fewer syscalls and faster installs.

  • Native publish flow. pnpm publish, login, logout, view, deprecate, unpublish, dist-tag, and version no longer delegate to the npm CLI.

  • .npmrc is auth/registry only. Other settings must live in pnpm-workspace.yaml or the new global config.yaml. Environment variables use the pnpm_config_* prefix.

重大变更

🌐 Breaking changes

要求

🌐 Requirements

  • Drops Node.js 18, 19, 20, and 21.

  • pnpm is now distributed as pure ESM.

  • The standalone exe requires glibc 2.27+.

安全与构建默认值

🌐 Security & build defaults

几个默认设置已切换为更安全的值:

🌐 Several defaults have flipped to safer values:

设置新默认值
minimumReleaseAge1440(1天)
minimumReleaseAgeStrictfalse
blockExoticSubdepstrue
strictDepBuildstrue
optimisticRepeatInstalltrue
verifyDepsBeforeRuninstall

新发布的软件包在至少 1 天后才会被解析。要选择退出,请在 pnpm-workspace.yaml 中设置 minimumReleaseAge: 0

🌐 Newly published packages won't be resolved until they're at least 1 day old. To opt out, set minimumReleaseAge: 0 in pnpm-workspace.yaml.

allowBuilds 替换了旧的构建设置

🌐 allowBuilds replaces the old build settings

onlyBuiltDependenciesonlyBuiltDependenciesFileneverBuiltDependenciesignoredBuiltDependenciesignoreDepScripts 都已被移除。请使用 allowBuilds 代替 — 一个从包名称模式到布尔值的映射:

之前:

🌐 Before:

onlyBuiltDependencies:
- electron
onlyBuiltDependenciesFile: "allowed-builds.json"
neverBuiltDependencies:
- core-js
ignoredBuiltDependencies:
- esbuild

之后:

🌐 After:

allowBuilds:
electron: true
core-js: false
esbuild: false

也已移除:allowNonAppliedPatches(使用 allowUnusedPatches)和 ignorePatchFailures(补丁失败现在会抛出)。

🌐 Also removed: allowNonAppliedPatches (use allowUnusedPatches) and ignorePatchFailures (patch failures now throw).

.npmrc 仅用于身份验证/注册表

🌐 .npmrc is auth/registry only

pnpm 不再从 .npmrc 读取非认证设置。配置分为两类:

🌐 pnpm no longer reads non-auth settings from .npmrc. Configuration is split into two categories:

  • Registry and auth settings — INI files (.npmrc, the global rc file, ~/.config/pnpm/auth.ini).

  • pnpm-specific settings — YAML files (pnpm-workspace.yaml, the new global ~/.config/pnpm/config.yaml).

其他相关变化:

🌐 Other related changes:

  • pnpm no longer reads npm_config_* environment variables. Use pnpm_config_* instead (e.g. pnpm_config_registry).

  • pnpm no longer reads the pnpm field in package.json.

  • pnpm no longer reads npm's global config at $PREFIX/etc/npmrc.

  • Network settings (httpProxy, httpsProxy, noProxy, localAddress, strictSsl, gitShallowHosts) are now written to config.yaml / pnpm-workspace.yaml (still readable from .npmrc to ease migration).

  • A new registries setting in pnpm-workspace.yaml replaces @scope:registry= lines:

    registries:
    default: https://registry.npmjs.org/
    "@my-org": https://private.example.com/
    "@internal": https://nexus.corp.com/
  • Per-project .npmrc is replaced by packageConfigs in pnpm-workspace.yaml:

    packages:
    - "packages/project-1"
    - "packages/project-2"
    packageConfigs:
    "project-1":
    saveExact: true
    "project-2":
    savePrefix: "~"

本地发布流程,不再使用 npm CLI 回退

🌐 Native publish flow, no more npm CLI fallback

以前通过传递到 npm CLI 实现的命令要么已被本地重新实现,要么已被移除

🌐 Commands previously implemented by passing through to the npm CLI have either been reimplemented natively or removed.

重新实现:publishviewinfoshowv)、loginadduser)、logoutdeprecateunpublishdist-tagversionsearchstar/unstar/starswhoamipingdocs/home

🌐 Reimplemented: publish, view (info, show, v), login (adduser), logout, deprecate, unpublish, dist-tag, version, search, star/unstar/stars, whoami, ping, docs/home.

已移除(现在抛出“未实现”):accessbugseditissuesownerprefixprofilepkgreposet-scriptteamtokenxmas

🌐 Removed (now throw "not implemented"): access, bugs, edit, issues, owner, prefix, profile, pkg, repo, set-script, team, token, xmas.

关于新的本地 pnpm publish 的一些说明:

🌐 A few notes on the new native pnpm publish:

  • The OTP environment variable is now PNPM_CONFIG_OTP (was NPM_CONFIG_OTP).

  • If the registry asks for OTP and none is provided, pnpm prompts for it interactively.

  • Web-based authentication shows a scannable QR code and URL.

pnpm audit 使用批量建议端点

🌐 pnpm audit uses the bulk advisories endpoint

注册表已淘汰了遗留的 /-/npm/v1/security/audits{,/quick} 端点。pnpm audit 现在调用 /-/npm/v1/security/advisories/bulk,它不返回 CVE 标识符 — 因此基于 CVE 的过滤已被 基于 GHSA 的过滤 所取代:

🌐 The legacy /-/npm/v1/security/audits{,/quick} endpoints have been retired by the registry. pnpm audit now calls /-/npm/v1/security/advisories/bulk, which doesn't return CVE identifiers — so CVE-based filtering has been replaced with GHSA-based filtering:

  • auditConfig.ignoreCvesauditConfig.ignoreGhsas

  • pnpm audit --ignore <id> and --ignore-unfixable read and write GHSAs

要迁移,请将 ignoreCves 下的每个 CVE-YYYY-NNNNN 条目替换为匹配的 GHSA-xxxx-xxxx-xxxx(在 pnpm auditMore info 列中可见),并将其移动到 ignoreGhsas

🌐 To migrate, replace each CVE-YYYY-NNNNN entry under ignoreCves with the matching GHSA-xxxx-xxxx-xxxx (visible in the More info column of pnpm audit) and move it to ignoreGhsas.

孤立的,全球虚拟商店的全球安装

🌐 Isolated, global-virtual-store global installs

pnpm add -g <pkg>pnx 现在使用全局虚拟存储,并且 每次安装都会在 {pnpmHomeDir}/global/v11/{hash}/ 获得自己的独立目录,该目录拥有自己的 package.jsonnode_modules/ 和锁文件。这可以防止全局包通过同辈依赖冲突、提升更改或版本漂移相互干扰。

  • pnpm remove -g <pkg> removes the entire installation group containing the package.

  • pnpm update -g [pkg] re-installs into a new isolated directory.

  • pnpm list -g scans isolated directories.

  • pnpm install -g (no args) is no longer supported — use pnpm add -g <pkg>.

全局安装的二进制文件现在位于 PNPM_HOMEbin 子目录中(而不是直接位于 PNPM_HOME),因此像 global/store/ 这样的内部目录不会污染 shell 自动补全。升级后运行 pnpm setup 以更新你的 shell 配置。

🌐 Globally installed binaries now live in a bin subdirectory of PNPM_HOME (rather than directly in PNPM_HOME), so internal directories like global/ and store/ don't pollute shell autocompletion. Run pnpm setup after upgrading to update your shell configuration.

pnpm link 也已被收紧:只接受相对路径或绝对路径,--global 已被移除(使用 pnpm add -g .),并且不带参数的 pnpm link 已被移除。

其他搬迁

🌐 Other removals

  • pnpm server.

  • useNodeVersion and executionEnv.nodeVersion — use devEngines.runtime / engines.runtime.

  • hooks.fetchers — replaced by the new fetchers field in pnpmfile.

  • managePackageManagerVersions, packageManagerStrict, and packageManagerStrictVersion. These all derived the onFail behavior of the legacy packageManager field; the new pmOnFail setting subsumes them:

    已移除替换为
    managePackageManagerVersions: truepmOnFail: download(默认)
    managePackageManagerVersions: falsepmOnFail: ignore
    packageManagerStrict: falsepmOnFail: warn
    packageManagerStrictVersion: truepmOnFail: error
    COREPACK_ENABLE_STRICT=0pmOnFail: warn

新命令

🌐 New commands

命令它的作用
pnpm ci运行 pnpm clean,然后运行 pnpm install --frozen-lockfile。别名:clean-installicinstall-clean
pnpm clean从所有工作区项目中移除 node_modules--lockfile 还会移除 pnpm-lock.yaml
pnpm sbom生成 CycloneDX 1.7 或 SPDX 2.3 JSON 格式的软件物料清单。
pnpm peers check报告锁文件中未满足或缺失的依赖。
pnpm runtime set安装运行时;不推荐使用 pnpm env use
pnpm docs / home打开软件包主页。
pnpm pingPing 注册表。
pnpm with在单次调用中以特定(或当前)版本运行 pnpm,绕过 packageManager 固定版本。
pnpm pack-app通过 Node.js SEA 将 CommonJS 入口打包为一个或多个目标平台的独立可执行文件。

再加上上文“本地发布流程”下列出的本地重新实现的命令,以及 pnpm 的短别名 pnpnpx/pnpm dlx 的短别名 pnx

🌐 Plus the natively reimplemented commands listed under "Native publish flow" above, and short aliases pn for pnpm and pnx for pnpx/pnpm dlx.

pnpm audit --fix=update

通过更新锁文件中的包来修复漏洞,而不是添加覆盖。为了更精细的控制,新的 --interactive / -i 标志允许你选择要修复的安全公告:

🌐 Fix vulnerabilities by updating packages in the lockfile instead of adding overrides. For more granular control, the new --interactive / -i flag lets you select which advisories to fix:

pnpm audit --fix=update --interactive

pnpm audit --fix 还将每个公告的最小修补版本添加到 minimumReleaseAgeExcludepnpm-workspace.yaml 中,因此可以在无需等待 minimumReleaseAge 的情况下安装安全修复。

ESM pnpm文件

🌐 ESM pnpmfiles

Pnpm 文件现在可以使用 ESM 编写,使用 .mjs 扩展名。当存在 .pnpmfile.mjs 时,它优先于 .pnpmfile.cjs,并且只加载一个。

🌐 Pnpmfiles can now be written in ESM, using the .mjs extension. When .pnpmfile.mjs exists, it takes priority over .pnpmfile.cjs, and only one is loaded.

商店 v11

🌐 Store v11

该商店围绕两个理念重建:少读数据,减少系统调用。

🌐 The store has been rebuilt around two ideas: read less, do fewer syscalls.

  • The package index is now a single SQLite database at $STORE/index.db (with MessagePack values, WAL mode for concurrent access), instead of millions of JSON files under $STORE/index/. Packages missing from the new index are re-fetched on demand.

  • The bundled manifest (name, version, bin, engines, scripts, etc.) is stored directly in the package index, eliminating the need to read package.json from the CAS during resolution and installation.

  • Index entries store hex digests instead of full integrity strings (<algo>-<digest>), and the hash algorithm is recorded once per file instead of per entry. This avoids base64 → hex conversion on every CAS path lookup.

  • When the global virtual store is enabled, packages that aren't allowed to build (and don't transitively depend on packages that are) get hashes that don't include the engine name (platform, arch, Node.js major). ~95% of GVS packages now survive Node.js upgrades and architecture changes without re-import.

性能

🌐 Performance

许多小的胜利累积起来会显著加快安装速度:

🌐 A lot of small wins add up to a noticeably faster install:

  • undici replaces node-fetch for all HTTP, with Happy Eyeballs (dual-stack), better keep-alive, and an optimized global dispatcher.

  • Tarball downloads with known size pre-allocate memory to avoid double-copy overhead.

  • The metadata cache is now NDJSON, with If-Modified-Since for conditional fetches.

  • minimumReleaseAge checks use the abbreviated metadata endpoint to fetch less.

  • CAS files are written directly to their content-addressed path instead of via a temp file + rename — saving ~30k rename syscalls per cold install.

  • The staging directory is gone when importing into node_modules.

  • Hot-path string operations in the CAS were tightened, and gunzipSync runs with a larger chunk size for fewer buffer allocations during tarball decompression.

  • During GVS warm reinstalls, redundant internal linking is skipped when no packages were added.

更精简的运行时安装

🌐 Slimmer runtime installs

通过 node@runtime:<version> 安装 Node.js 运行时(包括 pnpm env usepnpm runtime set node不再从 Node.js 压缩包中提取打包的 npmnpxcorepack。这样大约减少了一半 pnpm 需要哈希、写入 CAS 并链接的文件。如果你仍然需要 npm,请将其作为单独的包安装。

🌐 Installing a Node.js runtime via node@runtime:<version> (including pnpm env use and pnpm runtime set node) no longer extracts the bundled npm, npx, and corepack from the Node.js archive. That cuts roughly half of the files pnpm has to hash, write to the CAS, and link. If you still need npm, install it as a separate package.

其他显著变化

🌐 Other notable changes

  • Cleaner script output. pnpm now prints $ command (to stderr, so stdout stays pipe-friendly) instead of > pkg@version stage path\n> command. Project name and path are shown only when running in a different directory.

  • Peer dependency issues are no longer rendered as a tree during install — pnpm suggests running pnpm peers check to view them.

  • Lifecycle scripts no longer get npm_config_* env vars from the pnpm config; only well-known npm_* env vars are set, matching Yarn.

  • pnpm init writes devEngines.packageManager instead of packageManager when init-package-manager is enabled, and the default type is now "module".

  • devEngines.packageManager now supports version ranges; the resolved version is stored in pnpm-lock.yaml and reused if it still satisfies the range.

  • dedupePeers is a new setting that uses version-only suffixes (name@version) instead of full dep paths, eliminating nested suffixes like (foo@1.0.0(bar@2.0.0)) for projects with many recursive peers.

  • pnpm approve-builds now accepts positional arguments for non-interactive use; prefix a name with ! to deny it.

  • Hidden scripts — scripts starting with . can only be called from other scripts and don't show up in pnpm run.

  • -F is a new short alias for --filter.

  • pnpm add short flags-d is now --save-dev, -p is --save-prod, -o is --save-optional, -e is --save-exact (only inside pnpm add).

  • virtualStoreOnly populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. Useful for pre-populating a store in Nix builds. pnpm fetch now uses this internally.

  • nodeDownloadMirrors in pnpm-workspace.yaml replaces the node-mirror:<channel> .npmrc setting:

    nodeDownloadMirrors:
    release: https://my-mirror.example.com/download/release/
  • Config dependencies are now installed into {storeDir}/links/ and symlinked into node_modules/.pnpm-config/, so they're shared across projects using the same store. Resolved versions and integrity hashes have moved from pnpm-workspace.yaml to a separate document in pnpm-lock.yaml; old inline-hash projects are migrated automatically.

升级

🌐 Upgrading

请参阅完整的 从 v10 迁移到 v11 指南,以了解 codemod 和手动后续步骤。简短版本如下:

🌐 See the full Migrating from v10 to v11 guide for the codemod and manual follow-ups. The short version:

  • Bump your CI and dev environments to Node.js 22+ before upgrading.

  • Move pnpm settings out of .npmrc into pnpm-workspace.yaml (or the global ~/.config/pnpm/config.yaml).

  • Migrate onlyBuiltDependencies and friends to allowBuilds.

  • Migrate auditConfig.ignoreCves to auditConfig.ignoreGhsas.

  • After installing v11, run pnpm setup to update your shell so the new bin subdirectory is on PATH.

完整的更改列表请查看 changelog。如果你依赖的某些功能缺失或损坏,请在 github.com/pnpm/pnpm/issues 打开一个问题。

🌐 The full list of changes is in the changelog. If something you relied on is missing or broken, please open an issue at github.com/pnpm/pnpm/issues.