Langsung ke konten utama

pnpm 11.11-11.14

· Satu menit membaca
Zoltan Kochan
Lead maintainer of pnpm

pnpm 11.11 through 11.14 add native workspace release management (pnpm change, pnpm lane, and a bare pnpm version -r), a pnpm doctor command that diagnoses your installation end to end, the pnpm access and pnpm team commands for managing packages and organizations on the registry, convergence overrides, and scheme-carrying peerDependencies specifiers. They also fix a path-traversal vulnerability, cut peak memory during cold-cache resolution by roughly 30%, and resolve a peer dependency deadlock.

Minor Changes

Native workspace release management

pnpm can now version and release a workspace on its own, without a separate release tool (#12952). The new pnpm change command records change intents — changesets-compatible .changeset/*.md files naming the affected packages, their bump types, and a summary that becomes the changelog entry:

pnpm change
pnpm change status # show the pending release plan

At release time, the bare pnpm version -r consumes them, bumping versions across the workspace with dependent propagation through workspace: ranges, writing changelogs, and recording what it consumed in a committed ledger (.changeset/ledger.yaml) that keeps cherry-picks and merge-backs between release branches safe.

Packages can be moved onto per-package release lanes with pnpm lane, releasing X.Y.Z-lane.N prereleases from the same runs that release stable versions of everything else:

pnpm lane alpha --filter @example/cli   # move onto a lane
pnpm lane main --filter @example/cli # graduate back to stable

Configuration lives under the new versioning key of pnpm-workspace.yamlfixed, ignore, maxBump, lanes, epics, and changelog. Release changelogs default to registry storage: no CHANGELOG.md is committed, and each release's section is composed at publish time and packed into the published tarball. Set versioning.changelog.storage: repository to keep committed changelog files instead.

11.13 also added versioning.epics, which ties a group of member packages to a lead package, constraining every member's major version to a band derived from the lead's: while the lead is on major M, members live in M*100M*100+99. When a release plan takes the lead to a new stable major, every member re-bases to the band floor in the same plan.

See Release management for the whole workflow.

pnpm doctor

The new pnpm doctor command diagnoses the pnpm installation and the environment it runs in: the versions and install method, whether the global bin directory is on PATH, whether the store and cache are writable, which link strategies (reflink, hardlink, symlink) the store's filesystem supports, registry connectivity, and an offline file: install that exercises the resolve/store/link path end to end.

✓ Versions: pnpm 11.14.0, Node.js 22.20.0
✓ Install method: pnpm
✓ Global bin directory: /Users/example/Library/pnpm/bin
✓ Cache directory: /Users/example/Library/Caches/pnpm
✓ Store directory: /Users/example/Library/pnpm/store/v10
✓ Filesystem: available: reflink, hardlink, symlink
✓ Registry connectivity: https://registry.npmjs.org/ (128ms)
✓ Install smoke test: offline "file:" install linked its dependency

All checks passed

Each check reports how to fix what it finds, and the command exits non-zero when any check fails. Use --offline to skip the checks that need network access, --json for machine-readable output, and --benchmark to time the filesystem and install checks.

pnpm access and pnpm team

pnpm access manages package access and visibility on the registry — listing packages and collaborators, getting and setting package status and MFA requirements, and granting or revoking team access:

pnpm access list packages @myorg
pnpm access set status=public @myorg/pkg
pnpm access grant read-write @myorg:developers @myorg/pkg

pnpm team manages organization teams and memberships, with create, destroy, add, rm, and ls subcommands:

pnpm team create @myorg:developers
pnpm team add @myorg:developers alice
pnpm team ls @myorg

Convergence overrides

A new override selector form with an empty range"pkg@": "<version>" — rewrites a dependency edge only when its exact version satisfies the edge's declared range, so compatible consumers converge on one version while incompatible consumers keep their own resolution, now and for any dependent added in the future (#12794):

overrides:
"form-data@": 4.0.6

The value must be an exact version. When a full resolution detects that every declared range also admits a newer version, pnpm warns that the override is stale and names the version to converge on. Previously an empty range in an override selector was undocumented and behaved like a bare (unscoped) override.

peerDependencies accept scheme-carrying specifiers

peerDependencies now accept dependency specifiers that carry a scheme — a named-registry spec (<registry>:<version>), an npm: alias, or a file:/git/URL spec — instead of rejecting them with ERR_PNPM_INVALID_PEER_DEPENDENCY_SPECIFICATION (#13095). Such a peer is matched against the semver range carried by the specifier (work:5.x.x is checked as 5.x.x, npm:bar@^5 as ^5), or against * when it carries no version, while the original specifier still selects the package to auto-install. Bare name@version values, which are almost always a mistake, are still rejected.

RegExp script selectors and --sequential for pnpm run

pnpm run again supports executing multiple scripts matching a RegExp (e.g. pnpm run "/^build:.*/"), now running matched scripts in deterministic lexicographical order. The --sequential (-s) option is restored as well, forcing workspaceConcurrency to 1 so matched scripts run one by one across and within packages.

Portable delegation for custom fetchers

Custom fetchers exported from a pnpmfile can now delegate by returning a { delegate: <resolution> } envelope: pnpm rewrites the package's resolution to the delegated shape and runs the built-in fetcher on it. This is the portable delegation form that also works in pacquet, where cafs and fetchers cannot be passed to the hook.

Other minor changes

  • allowBuilds entries for git-hosted packages can now match by repository URL without pinning the resolved commit hash, so trusted git repositories keep running their build scripts after branch updates without approving each new commit. Package-name-only rules still do not approve git-hosted artifacts.
  • registries and namedRegistries can now be configured in the global config.yaml file.

Security

  • Fixed a path traversal vulnerability where a dependency whose manifest name was a scoped path traversal (e.g. @x/../../../<path>) could be written outside node_modules to an attacker-controlled location during pnpm install, even with --ignore-scripts.
  • Prevented a crafted pnpm-lock.yaml from writing package content outside the virtual store. Dependency path keys that reconstruct to a path-traversal sequence are now rejected by the isolated linker and the Plug'n'Play resolver map, and traversals in the version-derived path segment are rejected under the global virtual store.
  • Updated adm-zip to prevent crafted ZIP archives from causing excessive memory allocation.
  • ${...} environment-variable placeholders in the httpProxy, httpsProxy, noProxy, proxy, and noproxy settings are no longer expanded when these settings come from a project's pnpm-workspace.yaml.
  • pnpm publish no longer prints credentials when the target registry is configured with inline user:pass@ credentials.
  • pnpm runtime set <name> <version> now validates its arguments, so an unsupported name or a comma can no longer be misread as a list of packages.
  • Broken-lockfile errors no longer include snippets of the lockfile's contents.
  • Rejected symlinked pnpm-lock.yaml files when reading or writing the env lockfile document.
  • pnpm self-update now honors trustPolicy=no-downgrade, and checks that the version it installed can run before making it the active pnpm.

Patch Changes

  • Reduced peak memory usage during cold-cache dependency resolution by roughly 30%, back in line with pnpm 10. The memoized metadata cache no longer retains each package's raw registry response body for the whole resolution phase.
  • Fixed an out-of-memory regression when workspace projects concurrently resolve a package with large registry metadata (#13077).
  • Fixed a deadlock in peer dependency resolution: pnpm install hung forever when a peer dependency cycle spanned a project's own dependencies and auto-installed peer providers, for example when installing electron-builder@26.15.3 (#12921).
  • Fixed peer dependency auto-install picking a version the peer range rejects. Peers are now deduplicated onto the highest preferred version that satisfies the declared range, and when none does, the range is resolved from the registry.
  • Fixed peer dependency resolution with autoInstallPeers when a workspace package depends on a version of a package that a transitive dependency's self-contained closure also provides for itself (#4993).
  • Fixed pnpm install failing with ERR_PNPM_LOCKFILE_IS_SYMLINK when pnpm-lock.yaml is a symlink, as build sandboxes such as Bazel and Nix stage it (#13073). An install that leaves the lockfile unchanged no longer rewrites it, so --frozen-lockfile no longer needs to write at all.
  • Fixed frozen installs incorrectly treating equivalent Git dependency specifiers as a stale lockfile (#13039).
  • Fixed pnpm update rewriting exact version pins that use the = operator (for example =3.5.1) to a caret range.
  • Fixed pnpm update removing transitive lockfile entries when dedupePeerDependents is disabled and the selected package is absent (#12456).
  • Failed instead of silently removing an optional dependency's locked entries from pnpm-lock.yaml when the registry cannot resolve it (#12853).
  • Retried package metadata requests when a registry or proxy returns 304 Not Modified to an unconditional request, and recovered from a metadata cache entry that disappears after a 304 (#12882).
  • Fixed the dependency status check wrongly reporting "up to date" when a package.json, .pnpmfile.cjs, or patch file was edited in the same second as the previous install, on filesystems that record mtimes at whole-second resolution.
  • pnpm deploy now supports workspaces that use catalogs, and local file: tarball dependencies keep their package name in the generated deploy lockfile.
  • pnpm pack now respects workspace-root .npmignore and .gitignore files, and no longer applies workspace-root ignore rules when a workspace package has its own .npmignore.
  • pnpm publish again sends the package's README to the registry as metadata, and --otp is now sent correctly for both pnpm publish --otp and pnpm publish --batch --otp.
  • pnpm outdated no longer checks the registry for dependencies resolved from local link:, file:, or workspace: references (#12827).
  • pnpm list and pnpm why no longer crash with EMFILE: too many open files when a project has a large number of unsaved dependencies.
  • pnpm cache delete now removes a package's metadata from every metadata cache directory (#12753).
  • Fixed orphaned child processes on Windows when pnpm exits on an error while commands spawned by pnpm exec or pnpm dlx are still running (#12406).
  • Kept the interactive minimumReleaseAge approval prompt visible during pnpm install, so the install no longer hangs on a question the user cannot see (#13019).
  • A tokenHelper set in the global pnpm auth.ini is no longer rejected as project-level configuration, and a helper that hangs is now killed after 60 seconds instead of leaving the command waiting forever.
  • pnpm add -g, pnpm update -g, pnpm setup, and the self-updater no longer fail with ERR_PNPM_MISSING_TIME when trustPolicy: no-downgrade or resolutionMode: time-based is set in the global config (#12883).
  • A project pinned to a broken pnpm release via packageManager or devEngines.packageManager now reports which release is broken and what to do about it, instead of failing inside the installer.
  • The published pnpm package no longer declares dependencies or devDependencies, so npm install of the tarball no longer tries to resolve internal-only packages (#12955).
  • Fixed an injected workspace dependency incorrectly staying as file: instead of deduping back to link: (#10433).
  • pnpm owner ls now reports authentication and authorization failures as dedicated errors that include the registry's response body.
  • Options that follow create, exec, or test appearing as a subcommand of another command are now parsed instead of being silently treated as positional parameters.
  • The changed-packages filter (--filter "...[<since>]") no longer allows an option-like <since> value to be interpreted as a git option, and the repository root is resolved to the nearest .git entry so the filter works in a git worktree.
  • verify-deps-before-run no longer spawns a pnpm install when pnpm is executed in a directory that has no package.json.
  • pnpm stage list now stops paginating after a fail-safe cap of 1000 pages.
  • Registered the pn alias in generated shell completion scripts, and fixed standalone installer downgrades from pnpm v12 to v11.