Fast, disk space efficient package manager
Last release today
26 Aug 2026
Ships on a steady schedule
a new release about every 8 days
Nearly every release is documented
notes for 58 of the last 60 stable releases
25 versions withdrawn
withdrawn after publishing
5 years old
567 releases · first in 2021
Release timeline
567 releases since 2021Releases
- 11.6.011 Jun 2026
Release notes
Open source →⚠️ Security fix — environment variables in a project
.npmrc(action may be required)Following GHSA-3qhv-2rgh-x77r, pnpm no longer expands
${ENV_VAR}placeholders that come from a repository-controlled config file, because a malicious repository could otherwise use them to leak your environment secrets (npm tokens, CI job tokens, etc.) to an attacker-controlled registry during install. This applies to:- the project/workspace
.npmrc—registry,@scope:registry, proxy URLs, URL-scoped keys (//host/…), and credential values (_authToken,_auth,_password,username,tokenHelper,cert,key); - registry URLs in
pnpm-workspace.yaml.
Environment variables are still expanded in trusted config: your user-level
~/.npmrc, the global config, CLI options, and environment config.If your authentication broke after upgrading, move the token out of the committed
.npmrc:# Writes to your user/global config, not the repository: pnpm config set "//registry.npmjs.org/:_authToken" "$NPM_TOKEN"Or keep the
${NPM_TOKEN}line but put it in your user-level~/.npmrcinstead of the repo. In GitHub Actions,actions/setup-nodewithregistry-urlalready writes a user-level.npmrc, soNODE_AUTH_TOKENkeeps working. For other CI where editing each pipeline is hard, setPNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc(orNPM_CONFIG_USERCONFIG=.npmrc) in the CI environment to declare the project.npmrctrusted.See https://pnpm.io/npmrc for full migration details.
Minor Changes
-
pnpm installcompletes without re-resolving whenpnpm-lock.yamlwas deleted butnode_modulesis intact: the up-to-date check now treats the current lockfile (node_modules/.pnpm/lock.yaml) — the record of what the previous install materialized — as the wanted lockfile, verifies the manifests still match it, restorespnpm-lock.yamlfrom it, and reports "Already up to date". Previously this scenario triggered a full resolution and a re-verification of every locked package against the registry. -
615c669: Added support for configuring URL-scoped registry settings through
npm_config_//…andpnpm_config_//…environment variables, for example:npm_config_//registry.npmjs.org/:_authToken=<token> pnpm_config_//registry.npmjs.org/:_authToken=<token>This provides a file-free way to supply registry authentication. Because the registry a value applies to is encoded in the (trusted) environment variable name, it is host-scoped by construction and cannot be redirected to another registry by repository-controlled config. The environment value is treated as trusted config: it takes precedence over a project/workspace
.npmrcbut is still overridden by command-line options. When the same key is provided through both prefixes,pnpm_config_wins. -
Raised the default network concurrency from
min(64, max(cpuCores * 3, 16))tomin(96, max(cpuCores * 3, 64)). Package downloads are I/O-bound, not CPU-bound, so deriving the floor from the core count left machines with few cores (for example 4-vCPU CI runners) downloading only 16 tarballs at a time and unable to saturate a low-latency registry. ThenetworkConcurrencysetting still overrides the default.
Patch Changes
- Improved the warning printed when a project
.npmrcuses an environment variable in a registry/proxy URL or in registry credentials. The message now explains why the setting was ignored and how to migrate it to a trusted source — for example by moving the line to the user-level~/.npmrcor runningpnpm config set "<key>" <value>— with a link to https://pnpm.io/npmrc. Thepnpm config setexample is only suggested when the key has no${...}placeholder, so the snippet is always safe to copy-paste. - Print a "Lockfile passes supply-chain policies (verified 2h ago)" message when lockfile verification is skipped because a cached verdict for the same lockfile content and policy is reused. Previously the cached short-circuit was completely silent, which made it look like the policy gate never ran #12324.
- Platform-specific optional dependencies are now skipped even when their
os/cpu/libcfields are missing from the registry metadata or the lockfile. Some registries strip these fields from the package metadata, which made pnpm download and install the binaries of every platform regardless ofsupportedArchitectures. The missing platform fields of an optional dependency are now inferred from its name (e.g.@nx/nx-win32-arm64-msvc→os: win32,cpu: arm64), so foreign-platform binaries are skipped without even downloading them #11702.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/openai_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/openai_light.svg" /> <img src="https://pnpm.io/img/users/openai_dark.svg" width="160" alt="OpenAI" /> </picture> </a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- the project/workspace
- 11.5.310 Jun 2026
Release notes
Open source →⚠️ Security fix — environment variables in a project
.npmrc(action may be required)Following GHSA-3qhv-2rgh-x77r, pnpm no longer expands
${ENV_VAR}placeholders that come from a repository-controlled config file, because a malicious repository could otherwise use them to leak your environment secrets (npm tokens, CI job tokens, etc.) to an attacker-controlled registry during install. This applies to:- the project/workspace
.npmrc—registry,@scope:registry, proxy URLs, URL-scoped keys (//host/…), and credential values (_authToken,_auth,_password,username,tokenHelper,cert,key); - registry URLs in
pnpm-workspace.yaml.
Environment variables are still expanded in trusted config: your user-level
~/.npmrc, the global config, CLI options, and environment config.If your authentication broke after upgrading, move the token out of the committed
.npmrc:# Writes to your user/global config, not the repository: pnpm config set "//registry.npmjs.org/:_authToken" "$NPM_TOKEN"Or keep the
${NPM_TOKEN}line but put it in your user-level~/.npmrcinstead of the repo. In GitHub Actions,actions/setup-nodewithregistry-urlalready writes a user-level.npmrc, soNODE_AUTH_TOKENkeeps working. For other CI where editing each pipeline is hard, setPNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc(orNPM_CONFIG_USERCONFIG=.npmrc) in the CI environment to declare the project.npmrctrusted.See https://pnpm.io/npmrc for full migration details.
Patch Changes
-
Stopped expanding environment variables in repository-controlled registry/proxy request destinations and registry credential values from
.npmrc, and in workspace registry URLs frompnpm-workspace.yaml. Move dynamic registry URL and token configuration to trusted user, global, CLI, or environment config. -
Resolve package-manager bootstrap dependencies with trusted user or CLI registry and network config, and reject package-manager env-lockfile records that do not use registry package paths with integrity-only resolutions before auto-switch execution.
-
Avoid writing
packageManagerDependenciestopnpm-lock.yamlwhen package manager policy is set toonFail: ignoreorpmOnFail: ignore#12228. -
Avoid running dependency-status auto-install when the dependency status is unavailable without a project manifest.
-
Using the
$version reference syntax inoverrides(e.g."react": "$react") now prints a deprecation warning. The syntax still works, but catalogs are the recommended way to keep an overridden version in sync with the rest of the workspace. Reference a catalog entry with thecatalog:protocol instead. -
Fixed
pnpm config get globalconfigto return the globalconfig.yamlpath again pnpm/pnpm#11962. -
Fixed bare
--colorso it does not consume the following CLI flag, allowing command shorthands like--parallelto expand correctly and forms likepnpm --color with current <command>to dispatch the inner command instead of failing withMISSING_WITH_CURRENT_CMD. -
Fix
pnpm installignoringenableGlobalVirtualStoretoggle by including it in the workspace state settings check #12142. -
Security: pnpm now verifies the npm registry signature of a package-manager binary before spawning it, so a cloned repository cannot make pnpm download and execute an arbitrary native binary.
This covers two paths that select an executable from repository-controlled input:
- pacquet install engine — declaring
pacquet(or@pnpm/pacquet) inconfigDependenciesopts in to pnpm's Rust install engine. pnpm now verifies that the installedpacquetshim and the host's@pacquet/<platform>-<arch>binary carry a valid npm registry signature for their exactname@version, and refuses to run pacquet (failing the command) if the signature does not verify or cannot be checked. The only graceful fallback to pnpm's own engine is when pacquet has no binary for the current platform. - automatic version switch /
self-update— thepackageManager/devEngines.packageManagerfield makes pnpm download and run a specific pnpm version. pnpm now verifies the registry signature ofpnpm,@pnpm/exe, and the host platform binary before installing/spawning them, and refuses to run an engine whose signature does not match a published, signed release. The check runs only on an actual download (store cache miss), so it does not add a network round trip to every command.
In both cases the signature is verified over the installed integrity, against npm's public signing keys that ship embedded in the pnpm CLI (like corepack), so bytes substituted via a tampered lockfile or a repository-controlled registry fail verification — and a registry the user did not vouch for cannot supply its own signing keys. The signed packument is fetched from the configured registry, so an npm mirror works transparently. Verification fails closed: if it cannot be completed (for example, the registry is unreachable), the command fails rather than running an unverified binary. The embedded keys are kept current by a release-time check against npm's signing-keys endpoint.
- pacquet install engine — declaring
-
Made peer-dependent deduplication deterministic. When a peer-suffixed package variant was a subset of two or more mutually incompatible larger variants, the variant it collapsed into depended on the order importers were resolved in, which varies between machines. This could resolve the same workspace to different lockfiles on different platforms and make
pnpm dedupe --checkalternate between passing and failing. -
Reject invalid package names and versions from staged tarball manifests before deriving filenames for
pnpm stage download. -
Clarified in CLI help that the pnpm store is trusted shared state and store integrity checks are corruption detection, not a tamper boundary for untrusted store writers.
-
Reject reserved manifest
binnames ("",".","..", and scoped forms such as@scope/..) when resolving a package's bins. These names previously passed the bin-name guard and, when joined to the global bin directory during global remove/update/add operations, could resolve to the global bin directory itself or its parent and have it recursively deleted. -
Require trusted package identity before package-name
allowBuildsentries can approve lifecycle scripts for git, git-hosted tarball, direct tarball, and local directory artifacts. To approve one of those artifacts explicitly, use its peer-suffix-free lockfile depPath as theallowBuildskey. Lockfile verification now rejects lockfiles where a registry-style dependency path (name@semver) is backed by a git, directory, or git-hosted tarball resolution (ERR_PNPM_RESOLUTION_SHAPE_MISMATCH), so the dependency path is a reliable artifact identity by the time scripts can run. -
Security: pnpm now verifies the OpenPGP signature of a downloaded Node.js runtime's
SHASUMS256.txtbefore trusting its integrity hashes.When a repository requests a Node.js runtime (e.g. via
devEngines.runtime/useNodeVersion), the download mirror is repository-configurable throughnode-mirror:<channel>. The integrity of the downloaded binary was only checked againstSHASUMS256.txtfetched from that same mirror — a circular check that a malicious mirror could satisfy by serving a tampered binary together with a matchingSHASUMS256.txt. pnpm then executes the binary (for example to run lifecycle scripts).pnpm now fetches
SHASUMS256.txt.sigand verifies the detached OpenPGP signature against the Node.js release team's public keys, which ship embedded in the pnpm CLI. A mirror that serves a tampered binary cannot also produce a valid signature, so the download fails to verify. The embedded keys are kept current by a release-time check against the canonicalnodejs/release-keyslist.The musl variants from the hardcoded
unofficial-builds.nodejs.orgmirror are not repository-configurable and are signed by a different key, so they continue to be trusted over TLS.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/openai_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/openai_light.svg" /> <img src="https://pnpm.io/img/users/openai_dark.svg" width="160" alt="OpenAI" /> </picture> </a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- the project/workspace
- 11.5.25 Jun 2026
Release notes
Open source →Patch Changes
-
Peer dependency resolution now reuses the peer contexts already recorded in the lockfile when those providers are still present in the dependency graph and still satisfy the peer ranges. This avoids unnecessary peer-context rewrites during lockfile regeneration. Current manifest choices remain authoritative: a newly added, explicitly updated, or aliased direct provider, a changed nested provider, or a locked version that no longer satisfies the range still takes precedence.
-
The lockfile verifier now checks that a registry entry pinning an explicit
tarballURL points at the artifact the registry's own metadata lists for thatname@version. Previously a tampered lockfile could pair a trustedname@versionwith an attacker-chosen tarball URL (and a matching integrity for those bytes), so the install fetched the attacker's bytes. A mismatch — or any entry that can't be confirmed against the registry — is rejected withERR_PNPM_TARBALL_URL_MISMATCH. Non-registry resolutions (file:, git-hosted, etc.) and registry entries without an explicit tarball URL (the URL is reconstructed from name+version+registry, so it is inherently bound) are unaffected; non-standard registry tarball URLs (npm Enterprise, GitHub Packages) still pass because they match the metadata. -
Fix
pnpm update --recursive --lockfile-only <pkg>@<version>crashing withInvalid Versionwhen the catalog entry for<pkg>is a version range (e.g.^21.2.10) andcatalogModeisstrictorprefer. The catalog–version comparison now skips the equality check when either side is a range rather than passing a range tosemver.eq(), so range specifiers fall through to the existing mismatch handling instead of throwing #11570. -
Avoided a Node.js crash when pnpm exits after network requests on Windows.
-
Fixed packages being materialized into the virtual store without their root-level files (
package.json,LICENSE, README, root entrypoints) when multiplepnpm installprocesses ran against the same store/workspace concurrently. The fast import path used to destructively empty the shared target directory, so a concurrent importer could wipe files another importer had already written; if the surviving files included thepackage.jsoncompletion marker, every later install treated the broken directory as complete and never repaired it. The fast path now imports directly only when it can create the target directory exclusively, and otherwise builds the package in a private temp directory and atomically renames it into place #12197. -
Fix dependency build scripts not running under the global virtual store (
enableGlobalVirtualStore).In a workspace install, dependency build scripts are deferred to a single
rebuildpass (buildProjects). That pass resolved each package's location from the classicnode_modules/.pnpm/<depPathToFilename>layout, which does not exist under the global virtual store — so native dependencies (e.g. packages usingnode-gyp/prebuild-install) were never built and failed to load at runtime (Cannot find module .../build/Release/*.node).buildProjectsnow resolves the global-virtual-store projection directory (<storeDir>/links/<hash>, computed with the same graph hash the installer uses) whenenableGlobalVirtualStoreis set, and serializes concurrent builds of the same shared projection so parallel workspace projects don't race on the same directory. -
Don't promote a
runtime:dependency (such as the Node.js version fromdevEngines.runtimeorpnpm runtime set) into a catalog whencatalogModeisstrictorprefer. Aruntime:dependency round-trips todevEngines.runtime, which only recognizes theruntime:protocol; cataloging it rewrote the manifest entry tocatalog:, which broke that round-trip, stranded it indevDependencies, and leftdevEngines.runtimeuntouched. -
Skip lockfile
minimumReleaseAge/trustPolicyverification for non-registry tarball protocols (for examplefile:), so local tarball dependencies are not incorrectly checked against npm registry metadata.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.5.12 Jun 2026
Release notes
Open source →Patch Changes
- Improve
pnpm auditperformance by pruning non-vulnerable lockfile subtrees and stopping path enumeration once vulnerable findings reach the path cap. - Avoid crashing when the workspace state cache is partially written or malformed.
- Set
npm_config_user_agentfor root lifecycle scripts during headless installs. - Preserve the
integrityfield of a remote (non-registry) tarball dependency when its lockfile entry is rebuilt. Re-resolving such a dependency without re-fetching it (for example viapnpm update, or when another dependency changes) produced a resolution with no integrity — URL/tarball resolvers only learn the integrity after the tarball is downloaded — so the previously recorded integrity was dropped, making later installs fail withERR_PNPM_MISSING_TARBALL_INTEGRITY#12067. - Normalize a string
repositoryfield into the{ type, url }object form when creating the publish manifest, matching npm's behavior. Some registries (e.g. Gitea/Codeberg) reject a stringrepositorywith a 500 Internal Server Error duringpnpm publish#12099. - Preserve compatible optional peer versions already present in the lockfile when resolving dependencies.
- Fixed inconsistent resolution of a peer dependency that is shared through a diamond. When a package peer-depends on both another package and one of that package's own peer dependencies (for example
@typescript-eslint/eslint-pluginpeer-depends on both@typescript-eslint/parserandtypescript, and@typescript-eslint/parserpeer-depends ontypescript), pnpm no longer reuses a hoisted instance of the shared peer that was resolved against a different version #12079.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Improve
- 11.5.029 May 2026
Release notes
Open source →Minor Changes
-
Added a new
hoistingLimitssetting fornodeLinker: hoistedinstalls, mirroring yarn'snmHoistingLimits. It acceptsnone(the default — hoist as far as possible),workspaces(hoist only as far as each workspace package), ordependencies(hoist only up to each workspace package's direct dependencies). Originally proposed in #6468, closing #6457. -
Replaced
enquirerwith@inquirer/promptsfor all interactive prompts. Fixes theupdate -iscrolling overflow bug where long choice lists were clipped in the terminal #6643.User-facing changes:
pnpm update -i/pnpm update -i --latest: Scrolling now works correctly when many packages are available; the new library uses visual-line-aware pagination viausePaginationpnpm audit --fix -i: Same scrolling fix for vulnerability selectionpnpm approve-builds: Interactive build approval prompts updatedpnpm patch: Version selection and "apply to all" prompts updatedpnpm patch-remove: Patch removal selection updatedpnpm publish: Branch confirmation prompt updatedpnpm login: Credential prompts updatedpnpm run/pnpm exec(withverifyDepsBeforeRun=prompt): Confirmation prompt updated
Vim-style
j/kkeys still work for up/down navigation in all interactive prompts.Internal: The
OtpEnquirerandLoginEnquirerDI interfaces changed from{ prompt }to{ input }/{ input, password }respectively. Plugins or custom builds that inject their own enquirer mock will need to update. -
Staged publishes are now recognized in the trust scale. When a package version's registry metadata carries an
approverfield, it is treated as the strongest trust evidence (ranked above trusted publishers and provenance attestations), since staged publishes require 2FA publish approvals. This prevents false-positive trust downgrade errors when moving from a staged publish to a lower trust level #11887.
Patch Changes
-
Fix pnpm hanging during peer resolution when an aliased install pulls in transitive packages with mutual peer cycles at different depths in the dependency tree (for example,
pnpm i nuxt@npm:nuxt-nightly@5x). Cycles whose members hit thefindHitcache instead of running their owncalculateDepPathare now short-circuited by sibling resolutions at the level where the cycle is detected, so the cached path promises no longer deadlock. #11999. -
Fix
pnpm dist-tag addandpnpm dist-tag rmagainst npmjs.org failing without--otpwith[ERR_PNPM_UNAUTHORIZED] You must be logged in to set dist-tag … "You must provide a one-time pass. Upgrade your client to npm@latest in order to use 2FA.". pnpm now sendsnpm-auth-type: webon dist-tag writes and surfaces the resulting OTP challenge through the existing browser-based 2FA flow (the samewithOtpHandlinghelper used bypnpm publish), so the browser opens, the user authenticates, and the dist-tag is set on retry.--otp=<code>continues to work via the classic flow. -
Fix
minimumReleaseAgeExcludehandling in npm resolution fast paths so excluded packages do not get pinned to stale versions. Excludes are honored consistently duringpublishedBymetadata selection and cache-mtime shortcuts. -
Fix the
integrityfield being dropped from the lockfile entry of a remote (non-registry) https-tarball dependency when an unrelated package is installed afterwards. URL/tarball resolvers do not return an integrity (it is only known after the tarball is downloaded), so when such a dependency was reused from the lockfile without being re-fetched, its integrity was lost. It is now carried over from the existing resolution. With pnpm's lockfile-integrity hardening, the missing integrity made subsequent--frozen-lockfileinstalls fail withERR_PNPM_MISSING_TARBALL_INTEGRITY. #12001. -
Skip dependency re-resolution when
pnpm-lock.yamlis missing butnode_modules/.pnpm/lock.yamlexists and still satisfies the manifest.pnpm installnow reuses the materialized snapshot to regeneratepnpm-lock.yamlinstead of walking the registry to rebuild it from scratch, turning the cache+node_modules variation into a near-no-op for users who deleted the lockfile but kept the install #11993.--frozen-lockfilestill refuses to proceed whenpnpm-lock.yamlis absent — the regenerated lockfile must be committed, so failing loudly is the correct behavior for CI.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.4.027 May 2026
Release notes
Open source →Minor Changes
-
Treat tarball-integrity mismatches against the lockfile as a hard failure by default. Previously,
pnpm install(non-frozen) would logERR_PNPM_TARBALL_INTEGRITY, silently re-resolve from the registry, and overwrite the locked integrity — which meant a compromised registry, proxy, or republished version could substitute attacker-controlled content on a clean machine even though the project shipped a committed lockfile.pnpm installnow exits withERR_PNPM_TARBALL_INTEGRITYand a hint pointing at the new opt-in flag.The only opt-in is
pnpm install --update-checksums— narrowly scoped to refreshing the locked integrity values from what the registry currently serves. Mirrors yarn's flag of the same name. A warning still prints when the bypass takes effect so the operation is auditable.--forceandpnpm updatedeliberately do not bypass the integrity check. They are routine refresh operations; silently overwriting a locked integrity in those flows would erase the protection a committed lockfile is supposed to provide.--frozen-lockfilebehavior is unchanged.--fix-lockfilekeeps its documented purpose (filling in missing lockfile entries) and is also not a bypass. -
pnpm runtime set <name> <version>now saves the runtime todevEngines.runtimeby default instead ofengines.runtime. Pass--save-prod(or-P) to save it toengines.runtimeinstead #11948.
Patch Changes
-
Fix a credential disclosure issue where an unscoped
_authToken(or_auth, orusername+_password, ortokenHelper) defined in one source —~/.npmrc,~/.config/pnpm/auth.ini, a workspace.npmrc, CLI flags, etc. — would be sent as anAuthorizationheader to whichever registry a different (potentially untrusted) source named. The same fix extends to client TLS credentials (cert,key) so they aren't presented to a registry their author didn't choose.pnpm now rewrites each unscoped per-registry setting (
_authToken,_auth,username,_password,tokenHelper,cert,key) to its URL-scoped form at load time, using theregistry=value declared in the same source (or the npmjs default registry if the source declares none). A later layer overridingregistry=therefore cannot pull an unscoped credential along, because it is already pinned to the URL its author intended.ca/cafileare intentionally not rescoped — they're trust anchors, not credentials, and corporate MITM-proxy setups rely on them applying globally.Every rescope emits a deprecation warning telling the user where the setting was pinned and how to write it directly. npm has rejected unscoped credentials outright since
npm@9, and pnpm intends to remove support in a future major release. To target a specific registry, write the setting URL-scoped (e.g.//registry.example.com/:_authToken=...or//registry.example.com/:cert=...).@pnpm/network.auth-header: removed thedefaultRegistryparameter fromcreateGetAuthHeaderByURIandgetAuthHeadersFromCreds. Now that credentials are URL-scoped at load time, the mergedconfigByUrinever contains the empty-string "default registry" placeholder slot, so re-keying it onto the merged default registry is no longer needed. -
Fix
pnpm deploycrashing withENOENT: ... lstat '<deployDir>/node_modules'whenconfigDependenciesdeclares pacquet (pacquetor@pnpm/pacquet). The deploy directory never installs config dependencies, so the install engine they designate isn't on disk to invoke; the nested install now skips them. -
Reject git resolutions whose
commitfield is not a 40-character hexadecimal SHA before invokinggit. A malicious lockfile could otherwise smuggle a value such as--upload-pack=<command>throughgit fetch/git checkout, which on SSH or local-file transports executes the supplied command. -
Limit concurrent project manifest reads while listing large workspaces to avoid
EMFILEerrors. -
Reject patch files whose
diff --githeaders reference paths outside the patched package directory. Previously a malicious.patchfile added via a pull request could write, delete, or rename arbitrary files reachable by the user runningpnpm install. -
Improve the log message that pnpm prints after auto-adding entries to
minimumReleaseAgeExcludewhenminimumReleaseAgeis set withoutminimumReleaseAgeStrict. The message previously referred to the internal "loose mode" terminology, which wasn't searchable in the docs; it now tells the user to setminimumReleaseAgeStricttotrueif they want these updates gated behind a prompt instead #11747. -
Reject dependency aliases that contain path-traversal segments (such as
@x/../../../../../.git/hooks) when reading them from a package manifest or symlinking them intonode_modules. A malicious registry package could otherwise use a transitive dependency key to makepnpm installcreate symlinks at attacker-chosen paths outside the intendednode_modulesdirectory. -
Reject
pnpm-lock.yamlentries whose remote tarballresolution:block is missing theintegrityfield. Previously the worker that extracts a downloaded tarball skipped hash verification when no integrity was supplied and minted a fresh one from the unverified bytes, so an attacker who could both alter the lockfile (e.g. via a pull request that stripsintegrity:) and serve modified content at the referenced tarball URL could install a tampered package without any error — including under--frozen-lockfile. pnpm now fails closed at lockfile-read time withERR_PNPM_MISSING_TARBALL_INTEGRITY. Git-hosted tarballs (gitHosted: trueor a URL on codeload.github.com / bitbucket.org / gitlab.com) andfile:tarballs are exempt — the commit SHA in a git-host URL and the user-controlled local path already anchor the bytes. -
Validate
devEngines.runtimeandengines.runtimeversion ranges fornode,deno, andbunwhenonFailis set toerrororwarn. Previously these settings only had an effect withonFail: 'download'— theerrorandwarnmodes silently did nothing #11818. Violations now throwERR_PNPM_BAD_RUNTIME_VERSION. -
Require provenance before treating trusted publisher metadata as the strongest trust evidence.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.3.024 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Minor Changes
-
Added
pnpm stagewithpublish,list,view,approve,reject, anddownloadsubcommands for npm staged publishing. -
Added a new setting
trustLockfile. Whentrue,pnpm installskips the supply-chain verification pass that re-appliesminimumReleaseAge/trustPolicy='no-downgrade'to every entry in the loaded lockfile. The install treats the lockfile as already-trusted — useful for closed-source projects where every commit comes from a trusted author. Defaults tofalse; verification stays on by default. Set inpnpm-workspace.yaml.Also cut the memory footprint of the verification pass itself: the per-(registry, name) trust-meta cache previously retained the full packument — dependency graphs, scripts, README, and per-version manifests — for the entire install. On large workspaces (
~4klockfile entries withminimumReleaseAge+trustPolicy: no-downgradeenabled) this could OOM CI runners with a 2GB heap cap. The cache now stores only the fields the trust check actually reads (time, per-version_npmUser.trustedPublisher,dist.attestations.provenance). The abbreviated-metadata cache is similarly projected to just the package-levelmodifiedfield and the set of currently-listed version names. Fixes #11860. -
Implemented
pnpm pkgcommand natively, followingnpm pkgstandards. -
Implemented
pnpm repocommand natively, followingnpm repostandards. -
Implemented
pnpm set-script(aliasss) natively. Adds or updates an entry in thescriptsfield of the project manifest, supportingpackage.json,package.json5, andpackage.yamlformats. -
Add a
skip-manifest-obfuscationoption forpnpm packandpnpm publish. When enabled, the originalpackageManagerfield and publish lifecycle scripts are kept in the packed/published manifest instead of being stripped. The pnpm-specificpnpmfield continues to be omitted.
Patch Changes
- Fixed
pnpm dlxfailing withERR_PNPM_NO_IMPORTER_MANIFEST_FOUNDwhen the installed package's CAS slot is missing itspackage.json. Observed in the wild forpnpm dlx node@runtime:<version>when the GVS slot was populated without the synthesized manifest runtime archives need (they don't ship apackage.jsonof their own, so the synthesized one is the only way it gets there; an existing slot from an earlier code path that skipped the synthesis stays incomplete). The bin link itself is wired up from the resolution and remains valid, sodlxnow falls back to the scopeless package name when the slot's manifest is unreadable — for single-bin packages (the dlx common case, including everyruntime:spec) this matches whatmanifest.binwould have named. Multi-bin packages already require--package=<spec> <bin>to disambiguate and don't enter this code path. - Fixed non-determinism in
pnpm dedupeandpnpm installwhen a dependency graph contains packages with transitive peer dependencies on each other (e.g.@aws-sdk/client-stsand@aws-sdk/client-sso-oidc) andauto-install-peersis enabled. The lockfile no longer flips between two equally-valid forms across consecutive runs. The root cause was thatresolveDependenciespushed onto itspkgAddresses/postponedResolutionsQueuearrays from insidePromise.all-spawned callbacks, so completion-order timing leaked into the array order and downstream cyclic-peer suffix assignment. Fixes #8155. - Fixed a regression introduced by #11711 where
pnpm add <github-shorthand>(and any other wanted-dependency whose alias can't be parsed from the user-supplied spec, e.g. tarball URLs orpnpm/test-git-fetch#sha) was silently dropped from the manifest update and frompendingBuilds. The alias-keyed lookup added in that PR couldn't find awantedDependencywhosealiaswasundefinedat parse time but resolved to a package name only after fetching, so the entry never made it intospecsToUpsert. Restored the original index-based pairing betweendirectDependenciesandwantedDependencies; the catalog-protocol preservation that PR was originally fixing is unaffected because it's driven byrdd.catalogLookup.userSpecifiedBareSpecifier, not by the lookup. Fixes the threerebuilds dependencies/rebuilds specific dependencies/rebuild with pending optionfailures inbuilding/commands/test/build/index.ts. - Fixed
pnpm add --configleaving orphan entries inpnpm-lock.env.yaml(the optional subdependencies of the previously resolved version of the updated config dependency).
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.2.221 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Minor Changes
-
Experimental: Adding
@pnpm/pacquet(the Rust port of pnpm) toconfigDependenciesinpnpm-workspace.yamlnow delegates the materialization phase ofpnpm installto the pacquet binary. pnpm still owns dependency resolution; pacquet only fetches and imports from the freshly-written lockfile. This is an opt-in preview of the Rust install engine #11723.To configure pacquet in a project, run:
pnpm add @pnpm/pacquet --configYou'll see changes in
pnpm-workspace.yamlandpnpm-lock.yamlthat should be committed. If you experience any issues with pacquet, please let us know by mentioning this in the GitHub issue you create.
Patch Changes
- When the install engine is delegated to pacquet via
configDependencies, the user's CLI flags passed topnpm install(e.g.--no-runtime,--prod,--dev,--no-optional,--node-linker,--cpu/--os/--libc,--offline,--prefer-offline) are now forwarded to pacquet'sinstallsubcommand verbatim. Previously pacquet was invoked with a fixed argument list, so flags like--no-runtimewere silently dropped. Flag forwarding is gated on the command beinginstall/i;add,update, anddedupestill don't forward (their flag surface doesn't line up with pacquet'sinstall). - Fixed
pnpm up(andpnpm add/pnpm remove) failing withpacquet_package_manager::outdated_lockfilewhen pacquet is declared inconfigDependencies. pnpm now passes--ignore-manifest-checkto pacquet so its--frozen-lockfilecheck doesn't fire against the (pre-mutation)package.jsonpnpm hasn't written yet #11797. Requires a pacquet release that supports the flag — bumpPACQUET_VERSIONin the e2e tests once it ships.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.2.120 May 2026
Release notes
Open source →Minor Changes
-
Experimental: Adding
@pnpm/pacquet(the Rust port of pnpm) toconfigDependenciesinpnpm-workspace.yamlnow delegates the materialization phase ofpnpm installto the pacquet binary. pnpm still owns dependency resolution; pacquet only fetches and imports from the freshly-written lockfile. This is an opt-in preview of the Rust install engine #11723.To configure pacquet in a project, run:
pnpm add @pnpm/pacquet --configYou'll see changes in
pnpm-workspace.yamlandpnpm-lock.yamlthat should be committed. If you experience any issues with pacquet, please let us know by mentioning this in the GitHub issue you create.
Patch Changes
- Mark optional subdependency snapshots of config dependencies with
optional: truein the env lockfile, matching how optional dependencies are recorded elsewhere inpnpm-lock.yaml. Previously, snapshots for the platform-specific subdeps pulled in via a config dep'soptionalDependencieswere written as empty objects, which was inconsistent with the rest of the lockfile and made it look like those non-host platform variants were required. - Fix
pickRegistryForPackagereturning the wrong registry for an unscopednpm:alias under a scoped local name. A manifest entry like"@private/foo": "npm:lodash@^1"was routing thelodashfetch throughregistries["@private"], even thoughlodashis unscoped and doesn't live on that registry. The npm-alias branch now returns the alias target's own scope (ornullfor an unscoped target, falling through toregistries.default) instead of leaking into the local key's scope. - Don't print "Installing config dependencies..." when config dependencies are already installed and nothing needs to be fetched, re-linked, or removed.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.2.020 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Minor Changes
-
Experimental: Adding
@pnpm/pacquet(the Rust port of pnpm) toconfigDependenciesinpnpm-workspace.yamlnow delegates the materialization phase ofpnpm installto the pacquet binary. pnpm still owns dependency resolution; pacquet only fetches and imports from the freshly-written lockfile. This is an opt-in preview of the Rust install engine #11723.To configure pacquet in a project, run:
pnpm add @pnpm/pacquet --configYou'll see changes in
pnpm-workspace.yamlandpnpm-lock.yamlthat should be committed. If you experience any issues with pacquet, please let us know by mentioning this in the GitHub issue you create. -
configDependenciesnow resolve and install one level ofoptionalDependenciesdeclared by the config dependency, withos/cpu/libcplatform filtering applied at install time. This unlocks the esbuild/swc-style pattern where a package ships platform-specific binaries viaoptionalDependencies— a config dependency can now do the same and have the matching binary symlinked next to it in the global virtual store, sorequire('pkg-platform-arch')from inside the config dependency resolves correctly.The env lockfile records all platform variants regardless of host platform, so it remains portable across machines. Each entry in a config dependency's
optionalDependenciesmust declare an exact version — ranges and tags are rejected to keep installs reproducible. -
Implement the documented
pnpm login --scope <scope>flag. The scope is normalized (a leading@is added if missing; blank values are ignored) and an@<scope>:registry=<registry>mapping is written to the pnpm auth file alongside the auth token. Subsequent installs of@<scope>/*packages then route to the chosen registry. Previouslypnpm login --scope fooerrored withUnknown option: 'scope'despite the flag being listed in the online documentation #11716. -
pnpm outdatedandpnpm update --interactivenow report Node.js, Deno, and Bun runtimes installed as project dependencies (runtime:specifiers). Previously these were silently skipped.
Patch Changes
-
Fix
cafile=<relative-path>in.npmrcbeing read from the wrong directory when pnpm is invoked from a different cwd (e.g.pnpm --dir <project> installfrom a CI wrapper or monorepo script). The path is now resolved against the directory of the.npmrcthat declared it, notprocess.cwd(). Before this fix the CA file silently failed to load — the install proceeded without the configured CA and the user only saw TLS errors against a private registry, with no log line tying back to the wrongly resolved path #11624. -
Fix
config.registrygetting a trailing slash appended whenregistryis set in.npmrcand noregistries.defaultis provided bypnpm-workspace.yaml. The sync fromregistries.defaulttoconfig.registryintroduced in #11744 now only fires when the workspace manifest actually contributes a different default. -
Fix global add/update to handle minimumReleaseAge policy violations instead of surfacing an internal resolver guardrail error.
-
Fix two crashes with
injectWorkspacePackages: truewhen the lockfile has been pruned (e.g. byturbo prune --docker):Cannot use 'in' operator to search for 'directory' in undefined: a peer-dependency-variant injected snapshot inherits itsresolutionfrom the basepackages:entry; when a pruner drops that base entry the readers crash.convertToLockfileObjectnow reconstructs the directory resolution from thefile:depPath at load time — a single normalization point, so every reader sees a fully-formed snapshot.ERR_PNPM_ENOENTonnode_modules/.bin/<tool>: afterprepare/postinstall,runLifecycleHooksConcurrentlyre-imported each injected workspace package; thescanDir-into-filesMapworkaround fed target-internal paths to the importer, which themakeEmptyDirfast path (#11088) then wiped. Drop the workaround and passkeepModulesDir: trueso the importer preserves the target's existingnode_modules(bin links + transitive deps) and source files keep their hardlinks.
-
Fixed
pnpm loginandpnpm logoutignoringregistries.defaultfrompnpm-workspace.yaml#10099. -
Fix the
minimumReleaseAge(publishedBy) maturity shortcut to be inclusive at the cutoff. Previously, abbreviated metadata whosemodifiedfield equalled the cutoff fell off the fast path and triggered a full-metadata re-fetch (or aMISSING_TIMEerror when full metadata wasn't permitted). Sincemodifiedis an upper bound on every version's publish time,modified == publishedByalready implies every version passes the per-version<=filter infilterPkgMetadataByPublishDate, so the shortcut now accepts the boundary case directly. Strictly>(was>=) at the rejection branch. -
Honor
publishConfig.accesswhen publishing packages.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.1.318 May 2026
Release notes
Open source →Patch Changes
-
pnpm installnow re-validatespnpm-lock.yamlentries against the activeminimumReleaseAgeandtrustPolicy: 'no-downgrade'policies before any tarball is fetched. Lockfiles resolved elsewhere (committed to the repo, restored from a CI cache, produced by an older pnpm) under a weaker or absent policy can no longer install a freshly-published or trust-downgraded version silently. Violating entries abort the install withERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION,ERR_PNPM_TRUST_DOWNGRADE, or the genericERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATIONwhen both policies trip in the same batch;minimumReleaseAgeExcludeandtrustPolicyExcludeare honored. Verification results are cached so repeat installs against an unchanged lockfile take a fast path, and pnpm shows a transient progress line while the registry round-trip runs.When fresh resolution picks an immature version, the behavior depends on
minimumReleaseAgeStrict:- Loose mode — the default, in effect whenever
minimumReleaseAgekeeps its built-in 24-hour value — auto-adds the immature picks tominimumReleaseAgeExcludeinpnpm-workspace.yamland lets the install proceed. A single info message lists what was persisted. - Strict mode in an interactive terminal collects every immature direct AND transitive pick in one pass and prompts once with the full list. Approving adds them to
minimumReleaseAgeExcludeand the install continues; declining aborts before the lockfile,package.json, ornode_modulesis touched. - Strict mode in CI (or any non-TTY context) aborts with
ERR_PNPM_NO_MATURE_MATCHING_VERSIONlisting every offending entry, instead of failing on the first one the resolver hit.
minimumReleaseAgeStrictauto-enables whenever the user explicitly setsminimumReleaseAge(CLI flag, env var, globalconfig.yaml, orpnpm-workspace.yaml); setminimumReleaseAgeStrict: falseto keep loose-mode auto-collect even with an explicitminimumReleaseAgevalue. Closes #10438, #10488, #11687. - Loose mode — the default, in effect whenever
-
Allow redundant trailing base64 padding in
.npmrcauth values and report invalid auth base64 with a pnpm error. -
Make
pnpm self-updaterespectminimumReleaseAge(andminimumReleaseAgeExclude) when resolving which pnpm version to install.When the
latestdist-tag points to a version newer than the configured age threshold,self-updatenow selects the newest mature version instead unless excluded byminimumReleaseAgeExclude.Also makes
dlxandoutdatedsurface invalidminimumReleaseAgeExcludepatterns under the sameERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDEerror code already used byinstall, instead of leaking the internalERR_PNPM_INVALID_VERSION_UNION/ERR_PNPM_NAME_PATTERN_IN_VERSION_UNIONcodes. -
Global installs respect global config build policy (e.g.,
dangerouslyAllowAllBuildsfrom config.yaml) when GVS is enabled #9249.The global virtual-store (GVS) default
allowBuilds = {}was applied before workspace manifest settings were read and before global config values (stripped byextractAndRemoveDependencyBuildOptions) were re-applied viaglobalDepsBuildConfig. This causedhasDependencyBuildOptionsto returntrue(because{}is not null), blocking restoration of global config values likedangerouslyAllowAllBuilds. As a result, global installs skipped all build scripts even when the config explicitly allowed them.This fix moves the GVS default to after workspace manifest reading and
globalDepsBuildConfigre-application, so that:- Workspace manifest
allowBuildstakes precedence (if present) - Global config
dangerouslyAllowAllBuildsis properly restored (if set and no workspace policy exists) - Empty
{}is only applied as a last resort when no policy is configured anywhere
- Workspace manifest
-
Honor
--silentwhenverifyDepsBeforeRun: installauto-installs dependencies beforepnpm runorpnpm exec, preventing install output from being written to stdout #11636. -
Fix lockfile parsing failures when
pnpm-lock.yamlcontains CRLF line endings and multiple YAML documents #11612. -
Anchor the side-effects-cache key and global-virtual-store hash to the project's script-runner Node —
engines.runtimepin when present, shellnodeotherwise — instead of pnpm's own runtime.ENGINE_NAME(the<platform>;<arch>;node<major>prefix used as the side-effects-cache key and the engine portion of the GVS hash) was computed fromprocess.version— the Node that runs pnpm itself. That was wrong in two situations:@pnpm/exeSEA bundle. The bundle has its own embedded Node, not thenodeon the user'sPATHthat actually spawns lifecycle scripts. Two pnpm installations on the same machine (one SEA, one npm-package) therefore disagreed on the cache key, partitioning the side-effects cache and the global virtual store across two Node majors even though both installs would run scripts on the same shellnode.engines.runtime/devEngines.runtimepin. When a project pins a Node version viadevEngines.runtime(pnpm v11+), pnpm downloads that Node intonode_modules/node/and uses it to run lifecycle scripts. But the hash still anchored to whichever Node ran pnpm itself, not to the pinned Node — so two installs of the same project with two different runner Nodes would still disagree on the GVS slot path even though scripts run on the same pinned Node.
Three changes:
@pnpm/engine.runtime.system-node-versionnow exportsengineName(nodeVersion?). Resolves the version in this order: explicit override →getSystemNodeVersion()(which already prefersnode --versionoverprocess.versionin SEA contexts) →process.version.@pnpm/deps.graph-hashernow exportsfindRuntimeNodeVersion(snapshotKeys)— scans an iterable of lockfile snapshot keys for anode@runtime:<version>entry and returns its bare version string.calcDepStateandcalcGraphNodeHash/iterateHashedGraphNodesaccept anodeVersion?(in the options bag for the first, as a trailing parameter / ctx field for the others), forwarded toengineName(). The default (no override) preserves the pre-change behaviour. The legacyENGINE_NAMEconstant in@pnpm/constantsis unchanged so external consumers and existing tests keep working; in non-SEA, non-pinned contexts every value lines up.- Every install-side caller of the graph-hasher (
@pnpm/installing.deps-resolver,@pnpm/installing.deps-restorer,@pnpm/installing.deps-installer,@pnpm/building.during-install,@pnpm/building.after-install,@pnpm/deps.graph-builder) now derives the project's pinned runtime viafindRuntimeNodeVersion(Object.keys(graph))once per invocation and threads it through.
On upgrade, two one-time GVS slot churns are possible:
- SEA-pnpm users without a runtime pin: slots that previously hashed under the embedded-Node major (e.g.
node26) now hash under the shell-Node major (e.g.node24), matching what pacquet, the npm-publishedpnpmpackage, and any other pnpm-compatible tool already produce. - Projects with a
devEngines.runtimepin: slots that previously hashed under the runner's Node major now hash under the pinned Node major, matching what the lifecycle scripts will actually run on.
In both cases the old slots become prune-eligible.
-
Resolve the GVS hash's engine portion per-snapshot when a dependency declares its own
engines.runtime, instead of using an install-wide value.Pnpm's resolver desugars a dep's
engines.runtimeintodependencies.node: 'runtime:<version>', and the bin linker spawns that dep's lifecycle scripts through the pinned Node downloaded into<pkgDir>/node_modules/node/. The GVS hash and the side-effects-cache key prefix were still anchored to the install-wide runtime — so a pinning snapshot's slot encoded the wrong Node major, and a reinstall on the same host could read the cached side-effects under a key whose<platform>;<arch>;node<major>triple disagreed with the Node the build actually ran on.Per-snapshot resolution now matches what
bins/linkeralready does on a per-package basis:@pnpm/deps.graph-hasheraddsreadSnapshotRuntimePin(children)— reads thenodeentry from one snapshot's graph children and extracts the version from anode@runtime:value. Pairs with the existingfindRuntimeNodeVersion(snapshotKeys)install-wide fallback (also now exported from@pnpm/deps.graph-hasherrather than@pnpm/engine.runtime.system-node-version, where it was a poor fit —system-node-versionis about probing the host Node, not parsing lockfile-derived strings).calcDepStateandcalcGraphNodeHashconsultreadSnapshotRuntimePin(graph[depPath].children)first and only fall back to the install-widenodeVersionparameter when the snapshot doesn't pin its own Node.
Pacquet mirrors the same precedence at the
calc_graph_node_hashcall site inpackage-manager/src/virtual_store_layout.rs— a newfind_own_runtime_node_major(snapshot)helper reads each snapshot'sdependenciesfor anodeentry withPrefix::Runtimeand overrides the install-wide engine when present.On upgrade, snapshots of dependencies that declare their own
engines.runtimere-hash under that dep's pinned Node instead of the install-wide value. The old slots become prune-eligible. Closes #11690. -
Fixed
pnpm publishfailing with a 404 when authentication relied on OIDC trusted publishing alongside an.npmrcwritten byactions/setup-node(_authToken=${NODE_AUTH_TOKEN}) withoutNODE_AUTH_TOKENbeing set. Unresolved${VAR}placeholders in auth values are now treated as empty rather than passed through verbatim, so the literal placeholder no longer surfaces as a bearer token when OIDC fallback is the intended auth source #11513. -
Fix
devEngines.packageManager(singular form, withoutonFail) defaulting toonFail: "error"instead of the documentedpmOnFail: "download". As a result, a project that pinned a different pnpm version viadevEngines.packageManagerand ranpnpm installfrom a mismatched pnpm version failed with a hard error, even though the migration table frommanagePackageManagerVersions: truetopmOnFail: download (default)promises the install would auto-download the wanted version #11676.The array form of
devEngines.packageManagerkeeps its existing per-element defaults (errorfor the last entry,ignorefor the rest), since those reflect explicit prioritization by the user. ExplicitonFailvalues continue to win. -
Fix
devEngines.packageManagernot writingpackageManagerDependenciestopnpm-lock.yamlwhen the lockfile lacks an env-doc entry. Previously the lockfile sync skipped resolution unless an existingpackageManagerDependencies.pnpmentry needed refreshing, so a fresh install withoutonFail: "download"left the resolved pnpm version unrecorded — contradicting the documented behavior that the resolved version is stored inpnpm-lock.yaml#11674. -
Warn when
package.jsoncontains a legacypnpmfield with settings pnpm no longer reads frompackage.json(e.g.pnpm.overrides,pnpm.patchedDependencies). Previously these were silently ignored after the upgrade from v10, leaving users unaware that their overrides/patched dependencies had stopped taking effect #11677.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.1.214 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Patch Changes
-
Strip
sec-fetch-*headers from outgoing HTTP requests. These headers are automatically added by undici'sfetch()implementation per the Fetch spec but cause Azure DevOps Artifacts to return HTTP 400 for uncached upstream packages, as ADO interprets them as browser requests #11572. -
Fix
minimumReleaseAgehandling for cached abbreviated metadata.The version-spec cache fast path no longer rethrows
ERR_PNPM_MISSING_TIMEunderstrictPublishedByCheck; it now falls through to the registry-fetch path, consistent with the adjacent mtime-gated cache block.When the registry returns 304 Not Modified for a package whose cached metadata is abbreviated (no per-version
time), pnpm now re-fetches withfullMetadata: trueifminimumReleaseAgeis active and the package was modified after the cutoff. The upgraded metadata is persisted to disk so subsequent installs don't repeat the fetch. Previously the abbreviated meta was used as-is and the maturity check fell back to its warn-and-skip path, silently bypassing the quarantine and emitting a misleading "metadata is missing the time field" warning.Closes #11619.
-
Fix
pnpm upgrade --interactive --latest -rnot respecting named catalog groups. Previously, upgrading a dependency using a named catalog (e.g."catalog:foo") would incorrectly rewritepackage.jsonto"catalog:"and place the updated version in the default catalog instead of the named one #10115. -
Fixed
optimisticRepeatInstallskippingpnpm-lock.yamlmerge conflict resolution when the existingnode_modulesstate appears up to date. -
Fix
minimumReleaseAge/resolutionMode: time-basedinstalls failing on lockfiles whosetime:block is missing entries. The npm-resolver's peek-from-store fast path now surfacespublishedAtfrom the lockfile rather than discarding it, and falls through to a registry metadata fetch when the time-based cutoff can't be computed from the data on hand.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.1.112 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Patch Changes
- Skip installability validation when scanning workspace projects in
checkDepsStatus(run byverifyDepsBeforeRun). Previously the status check calledfindWorkspaceProjects, which validates each project'senginesandos/cpu/libcand warns about useless fields in non-root manifests — work that the install pipeline already performs. With nonodeVersionthreaded through, the engine check also fell back to the system Node fromPATHand emitted spurious "Unsupported engine" warnings before scripts ran. Status-only callers now usefindWorkspaceProjectsNoCheck; install paths continue to validate. - Fixed
pnpm add <alias>:@scope/pkgfor named registries. The local resolver was claiming any specifier containing/as a local directory, sopnpm add bit:@teambit/bit(withbitconfigured undernamedRegistries) installed a bogus link tobit:@teambit/bit/instead of resolving from the configured registry. The local resolver now runs after the named-registry resolver in the resolution chain. - Updated
@zkochan/cmd-shimto 9.0.3. The sh shim it writes for.cmd/.battargets now escapes the/Cswitch as//C, so it survives the path translation Git Bash applies when launchingcmd.exe. Without this, a bare/Cwas rewritten toC:\before reaching cmd.exe — the switch was dropped, cmd started interactively, and the calling script saw the cmd banner instead of the wrapped command's output. Affects any cmd-shim-wrapped batch script invoked from Git Bash / MSYS / Cygwin on Windows. See pnpm/cmd-shim#55.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Skip installability validation when scanning workspace projects in
- 11.1.011 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Minor Changes
-
Added
pnpm audit signaturesto verify ECDSA registry signatures for installed packages against keys from/-/npm/v1/keys#7909. Scoped registries are respected, and registries without signing keys are skipped. -
Added support for installing packages from the GitHub Packages npm registry via a built-in
gh:prefix (e.g.pnpm add gh:@acme/private), and, more broadly, for arbitrary named registries in the style of vlt's named-registry aliases. Authentication is picked up from the existing per-URL.npmrcentries (e.g.//npm.pkg.github.com/:_authToken=...), so no separate auth mechanism is required.Additional aliases — or an override for the built-in
ghalias, for GitHub Enterprise Server — can be configured undernamedRegistriesinpnpm-workspace.yaml:namedRegistries: gh: https://npm.pkg.github.example.com/ work: https://npm.work.example.com/With this,
work:@corp/lib@^2.0.0resolves againsthttps://npm.work.example.com/. #11324. -
Allow setting sbom spec version using
--sbom-spec-version#11389. -
Add
--no-runtimeflag (config:runtime=false) to skip installing runtime entries (e.g. Node.js downloaded viadevEngines.runtime) without modifying the lockfile. The lockfile keeps the runtime entry so frozen-lockfile validation still passes; only the runtime fetch and.binlinking are skipped. Useful in CI matrices where the runtime is provisioned externally (e.g. viapnpm runtime -g set node <version>) beforepnpm installruns. -
Added the
pnpm bugscommand that opens a package's bug tracker URL in the browser. With no arguments, it reads the current project'spackage.json; with one or more package names, it fetches each package's metadata from the registry and opens its bug tracker. Falls back to<repository>/issueswhen thebugsfield is missing #11279. -
Added
pnpm ownercommand to manage package owners on the registry.
Patch Changes
-
Added "published X ago by Y" information to the
pnpm viewcommand output, similar tonpm view. This is useful when comparing againstminimumReleaseAge.For example,
pnpm view pnpmnow shows:published 17 hours ago by GitHub Actions -
pnpm publishnow honors the configured HTTP/HTTPS proxy (includinghttps_proxy/http_proxy/no_proxyenvironment variables) when polling the registry'sdoneUrlduring the web-based authentication flow. Previously the poll bypassed the proxy, causing the registry to respond403from a different source IP and the login to never complete #11561. -
pnpm add -gnow installs each space-separated package into its own isolated directory by default. To bundle multiple packages into the same isolated install (so that they share dependencies and are removed together), pass them as a comma-separated list. For example:pnpm add -g foo barinstallsfooandbaras two independent globals — removing one does not affect the other.pnpm add -g foo,bar qarbundlesfooandbarinto a single isolated install whileqaris installed on its own.
Related: #11587.
-
pnpm runtime set <name> <version>no longer fails in the root of a multi-package workspace with theADDING_TO_ROOTerror. Installing the workspace root is a valid target for a runtime, so the command now bypasses that safety check. -
Fix
pnpm --versionhanging for the lifetime of the worker pool after the version was printed.main.ts's--versionshort-circuit returned before reaching the command-handlerfinallythat callsfinishWorkers(), so the worker pool thatswitchCliVersionhad spawned during integrity resolution stayed alive and held the Node event loop open. The CLI entry now runsfinishWorkers()from its ownfinally, so every exit path tears the pool down.Repro:
pnpm --versionin a workspace whosedevEngines.packageManagerversion already matches the running pnpm +onFail: "download".switchCliVersionresolves the integrity (spawning workers), finds nothing to swap, returns. The version prints, then the process hangs.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.98 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Patch Changes
- Fixed installation of GitLab-hosted dependencies. pnpm now downloads the tarball from
https://gitlab.com/<user>/<project>/-/archive/<sha>/<project>-<sha>.tar.gzinstead of the GitLab API endpoint that contained an encoded slash (%2F) between user and project. The encoded slash both triggered406 Not Acceptableresponses from GitLab and produced virtual store directory names that Node refused to import (ERR_INVALID_MODULE_SPECIFIER) #11533. - Honor
NPM_CONFIG_USERCONFIG(and its lowercasenpm_config_userconfigform) as a low-priority fallback when locating the user-level.npmrc. This restores compatibility with environments that point npm at a custom auth file via that env var — most notablyactions/setup-node, which writes registry credentials to${runner.temp}/.npmrcand exportsNPM_CONFIG_USERCONFIGto reference it. Without this, GitHub Actions workflows usingactions/setup-nodeto authenticate to private registries broke after upgrading to pnpm v11. PNPM-prefixed env vars andnpmrcAuthFilefrom the globalconfig.yamlcontinue to take precedence #11539. - Fix
pnpm packnot bundling dependencies listed inbundleDependencies(orbundledDependencies). The npm-packlist upgrade in pnpm 11 changed its API to require the caller to pre-populate the dependency tree, which the wrapper was not doing —bundleDependencieswere silently dropped from the tarball #11519. - Fixed the pnpm CLI crashing with a confusing
SyntaxError: Invalid regular expression flagsinstead of printing a clear "requires Node.js v22.13" error when launched on an unsupported Node.js version. The Node.js version check inbin/pnpm.mjswas effectively dead code because the staticimportof the bundleddist/pnpm.mjswas hoisted by the ES module loader and parsed before the check could run #11546. - Fixed
pnpm --prefix=<dir> installoverwriting the existingpnpm-workspace.yamlin<dir>withset this to true or falseplaceholders. The renamed--prefixoption (which maps todir) was not honored when locating the workspace root, so the workspace manifest'sallowBuildssettings were not loaded into config and got clobbered when ignored builds were auto-populated #11535. - Fixed
pnpm publish --provenancefailing with a 422 from the registry when the package version contained semver build metadata (e.g.1.0.0-canary.0+abc1234). The+<build>segment is now stripped before packing so that the version embedded in the tarball, the metadata sent to the registry, and the sigstore provenance subject all agree #11518.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Fixed installation of GitLab-hosted dependencies. pnpm now downloads the tarball from
- 11.0.87 May 2026
Release notes
Open source →See full v11.0.0 changelog Migration guide: Migrating from v10 to v11
Patch Changes
- Restored the heuristic that preserves tarball URLs in
pnpm-lock.yamlwhen they cannot be derived from name+version+registry, even with the defaultlockfileIncludeTarballUrl: false. Without this,pnpm install --frozen-lockfilefrom an empty store fails withERR_PNPM_FETCH_404for packages on registries that serve tarballs from a non-standard path — most notably GitHub Packages (https://npm.pkg.github.com/download/<scope>/<name>/<version>/<hash>) and JSR.lockfileIncludeTarballUrl: truecontinues to force the URL into the lockfile for every package #11276. - Run
preversion,version, andpostversionlifecycle scripts forpnpm version. - Fixed
ERR_PNPM_BAD_TARBALL_SIZEwhen a registry serves tarballs with an end-to-endContent-Encoding(e.g.gzip). Tarballs are already compressed, so the fetcher now requests them withAccept-Encoding: identity(matching pnpm v10's effective behavior) and, as defense in depth against misbehaving servers, no longer enforces the strictContent-Lengthcheck when the response declares aContent-Encoding—Content-Lengthin that case refers to the encoded payload, not the decoded bytes the fetch implementation yields #11506.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Restored the heuristic that preserves tarball URLs in
- 11.0.76 May 2026
Release notes
Open source →Patch Changes
-
Restore the execute bit on the
node-gypshims packed inside@pnpm/exe(dist/node-gyp-bin/node-gyp,dist/node-gyp-bin/node-gyp.cmd, anddist/node_modules/node-gyp/bin/node-gyp.js). Without this,pnpm/action-setup's standalone path (used on runners with Node.js < 22.13) failed any install whose lifecycle script invokednode-gyp rebuildwithsh: 1: node-gyp: Permission denied#11483. -
Fixed the
pn,pnpx, andpnxaliases failing in Git Bash / MSYS2 on Windows when pnpm was installed via@pnpm/exe(or afterpnpm self-update) #11486. Runningpnpx(orpnx) printed the cmd.exe banner and dropped the user into an interactive command prompt instead of runningpnpm dlx. Thebinfield rewrite on Windows was pointing those aliases at.cmdfiles; cmd-shim's Bash shim for a.cmdtarget wraps it inexec cmd /C ..., and MSYS2 mangles/Cinto a Windows path before cmd.exe sees it. The aliases are now.exehardlinks of the SEA binary, which detects which name it was launched as viaprocess.execPathand prependsdlxforpnpx/pnx. -
Fix
pnpm installrecreatingnode_modulesafterpnpm fetch.pnpm fetchrecords emptyhoistPatternandpublicHoistPatternin.modules.yaml; since v11 removed the explicit-config gate, the follow-up install treated those as a hoist-pattern change and purged the modules directory. The fetch step now flags the modules manifest withvirtualStoreOnly: trueso the next install skips the hoist-pattern comparison and completes the missing post-import linking in place #11488. -
Pin the integrity of git-hosted tarballs (codeload.github.com, gitlab.com, bitbucket.org) in the lockfile so that subsequent installs detect a tampered or substituted tarball and refuse to install it. Previously the lockfile only stored the tarball URL for git dependencies, so a compromised git host or a man-in-the-middle could serve arbitrary code on later installs without lockfile changes.
A new
gitHosted: truefield is recorded on git-hosted tarball resolutions in the lockfile, letting every reader/writer route them by a single typed check instead of pattern-matching the tarball URL in each call site. Lockfiles written by older pnpm versions are enriched on load (URL fallback) so the field can be relied on uniformly across the codebase. -
Allow user-level preferences in the global
config.yaml. The following settings can now be set in~/.config/pnpm/config.yaml(or viapnpm config set --location global) instead of being restricted topnpm-workspace.yaml:agent,globalVirtualStoreDir,initPackageManager,initType,registrySupportsTimeField,scriptShell,shellEmulator,sideEffectsCache,sideEffectsCacheReadonly,stateDir,strictDepBuilds,trustPolicy,trustPolicyExclude,trustPolicyIgnoreAfter,updateNotifier,useStderr,verifyDepsBeforeRun,verifyStoreIntegrity,virtualStoreDir,virtualStoreDirMaxLength#11474. -
Make trusted publishing (OIDC) take precedence over a configured static
_authTokeninpnpm publish, mirroring the npm CLI's behavior. When OIDC succeeds, the OIDC-derived token overrides any pre-configured_authToken; when OIDC is not applicable (no CI environment, exchange fails, registry has no trusted publisher configured), the static token is used as a fallback. This applies on every package during recursive publish, so each workspace package independently attempts trusted publishing.Additionally, the
NPM_ID_TOKENenv var is now honored as a CI-agnostic injection point for an OIDC ID token. Previously OIDC was only attempted on GitHub Actions or GitLab; now any CI provider that exposes its own OIDC mechanism (e.g. CircleCI'sCIRCLE_OIDC_TOKEN_V2, Buildkite, etc.) can forward its token viaNPM_ID_TOKENand trusted publishing will work without pnpm needing to recognize the provider explicitly. -
--pm-on-fail=ignore(and other universal options like--loglevel,--reporter) is now honored when combined with--helpor--version. Previously the CLI argument parser short-circuited those flags before universal options were preserved, sopnpm audit --pm-on-fail=ignore --helpandpnpm --pm-on-fail=ignore --versionreported the strict packageManager mismatch instead of running the requested action #11487. -
Fix a regression where
pnpm --recursive --filter '!<pkg>' run/exec/test/addwould include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative--filterarguments are provided, matching the documented behavior. To include the root, pass--include-workspace-root#11341. -
Restore npm-CLI-compatible
--jsonstdout output forpnpm publish(#11476). pnpm 11 reimplemented publish natively (#10591) and inadvertently dropped the per-package JSON object that pnpm 10 emitted transitively via the npm CLI, silently breaking downstream tooling — most notablynx release publish, which parses stdout JSON to confirm success (nrwl/nx#35575). On success, the output is now:pnpm publish --json→ single object{ id, name, version, size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled }, mirroringnpm publish --json.pnpm publish -r --json→ array of those objects, mirroringpnpm pack --json's shape choice.pnpm publish -r --report-summary→ existingpnpm-publish-summary.jsonenvelope{ publishedPackages: [...] }is preserved, but each entry is upgraded to the same per-package shape (additive —nameandversionare still present).
-
pnpm config get @<scope>:registrynow reports the same URL thatpnpm publishand the resolvers actually use. Previously,config getonly consulted.npmrc, whilepublish/install used the merged map that includespnpm-workspace.yaml'sregistriesblock — so the two could diverge silently and a publish could go to the wrong registry #11492.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.65 May 2026
Release notes
Open source →Patch Changes
- Fix
pnpm_config_npmrc_auth_fileandpnpm_config_userconfigenv vars not actually loading the custom.npmrc. The env vars were parsed and assigned to the resolved config, but only afterloadNpmrcConfighad already read the default~/.npmrc— so the custom file path was set but never read. The relevant env vars are now consulted before the user-level.npmrcis loaded #11465. - Preserve the original key order in
pnpm-workspace.yamlwhen updating it. Existing keys keep their position, and new keys are inserted in alphabetical position when the existing keys are already sorted (with a leadingpackageskey allowed) or appended at the end otherwise. - Fixed
pnpm self-updateon installations originally set up by pnpm v10. v10 addedPNPM_HOMEdirectly to PATH and wrote apnpmbootstrap shim there. v11 setup writes shims underPNPM_HOME/bininstead, so when a v10 user upgrades to v11 the legacy shim atPNPM_HOMEkeeps pointing into the old.tools/<version>install —pnpm --versioncontinues to report the pre-update version even though the new version was installed underglobal/v11. Self-update now detects this layout, refreshes the legacy shims so the upgrade actually takes effect, and prints a hint suggestingpnpm setupto migrate PATH to the v11 layout. #11464. - Print a warning when settings that are not allowed in the global config file (e.g.
nodeLinker,hoistPattern) are present inconfig.yamland silently ignored. Previously these settings were dropped without any feedback, leaving users unsure why their global configuration had no effect. The warning suggests moving those settings to a project-levelpnpm-workspace.yaml, or sharing them across projects via config dependencies. - Throw a pnpm error when
overrideshas an invalid shape or contains a non-string value. - Validate all
readPackagedependency map fields, includingdevDependencies, and reject falsy non-object invalid values instead of silently accepting them. - Prevent crashes during
pnpm config,pnpm set, andpnpm getby toleratingconfigDependenciesinstall failures. For these commands, a failure to installconfigDependencies(for example because the registry auth token has not been written yet) is now logged at debug level and the command proceeds. All other commands still surface the install error #10684. - Treat
allowBuildsas an install-state input and clear previously ignored builds when they are explicitly disallowed. - Fixes #10594, catalogs not being read from the workspace when using the
catalog:protocol with thepnpm dlx/pnpxcommand, resulting in a catalog entry not found error. - Accept
PNPM_CONFIG_*(uppercase) environment variables in addition topnpm_config_*. Previously, only the lowercase form was honored, so env vars renamed per the v11 migration guide (e.g.PNPM_CONFIG_USERCONFIG) silently had no effect on case-sensitive systems like macOS and Linux #11465.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Fix
- 11.0.54 May 2026
Release notes
Open source →Patch Changes
-
Drop the
darwin-x64artifact from@pnpm/exeand from the GitHub release page. The Node.js SEA mechanismpnpm pack-appuses produces a binary that segfaults at startup on Intel Macs because of an upstream Node.js bug (nodejs/node#62893, tracked alongside #59553; the Node.js team has opted not to fix it on the grounds that x64 macOS is being phased out). Re-signing withcodesignorldiddoesn't help — the corruption is in LIEF's Mach-O surgery, before signing.Intel Mac users should install pnpm via
npm install -g pnpm(uses the system Node.js, no SEA), or stay on pnpm 10.x.@pnpm/exe's preinstall on Intel Mac now exits with a clear error pointing at these alternatives.Closes #11423.
-
pnpm dlx(andpnpx/pnx/pnpm create) now runs the same interactiveapprove-buildsprompt aspnpm add -gwhen the package being launched depends on transitive packages with install scripts. Previously, the v11strictDepBuildsdefault made dlx fail withERR_PNPM_IGNORED_BUILDSand required users to re-run with--allow-build=<pkg>for every offending dependency. dlx also now removes the partially-populated cache directory when the install fails, so a subsequent run starts clean instead of reusing a broken install whose builds were silently skipped #11444. -
72629fc: Fix
pnpm -g ls --jsonandpnpm -g ls --parseableso they emit valid JSON and parseable output respectively, matching pnpm 10 behavior. Since the isolated global packages refactor in pnpm 11, the global list command had a custom path that always printed plain text and ignored--json/--parseable, which broke tools likenpm-check-updatesthat parse the JSON output #11440.pnpm -g ls --depth=<n>(with n > 0) now errors when more than one isolated global install would be involved, since each install has its own lockfile and merging their transitive trees would be incoherent. When the request can be narrowed to a single install group, the regularlistflow is used and the full dependency tree is shown. -
Fixed
pnpm publishto honorpublishConfig.registryfrompackage.jsonwhen publishing a single package. The native publish flow introduced in v11 was reading the registry from.npmrconly, ignoring the per-package override #11419. -
When
strictPeerDependenciesistrue, theERR_PNPM_PEER_DEP_ISSUESerror once again renders the peer dependency issues inline using the same format aspnpm peers check, so users (and CI tools like Renovate) can see what failed without runningpnpm peers checkseparately #11439. -
The
WARNand error code labels in pnpm's output now wrap in brackets ([WARN],[ERR_PNPM_FOO]). Previously the labels relied entirely on a colored background to stand out, which meant they blended into the surrounding text in terminals without color (e.g. whenNO_COLORis set or output is piped). The brackets are painted in the same color as the badge background, so they appear as ordinary padding in color-capable terminals — only the no-color rendering changes.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.42 May 2026
Release notes
Open source →Patch Changes
- Fixed
pnpm cinot reinstalling workspace packagenode_modulesdirectories after the clean step #11427. - Remove pnpm's workspace state file when cleaning node_modules so
pnpm ciperforms a fresh install after the clean step. - Do not remove
pnpm-lock.yamlduringpnpm cleanwhenlockfile: trueis configured inpnpm-workspace.yaml. The lockfile is only removed when the--lockfileoption is passed topnpm clean. pnpm self-update(with no version argument) no longer downgrades pnpm when the registry'slatestdist-tag points to an older release than the currently active version. Runpnpm self-update latestto force a downgrade #11418.minimumReleaseAgeStrictnow defaults totruewhenever the user explicitly setsminimumReleaseAge(viapnpm-workspace.yaml, the globalconfig.yaml, the CLI, orpnpm_config_*env vars).
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Fixed
- 11.0.330 Apr 2026
Release notes
Open source →Patch Changes
- Fix too many open files error sometimes happening on Windows, when creating command shims in
node_modules/.bin#11412. - Fix
ERR_PNPM_FETCH_404when installing a project whose lockfile depends on afile:tarball. The previous behavior dropped thetarballfield fromfile:and git-hosted resolutions whenlockfile-include-tarball-url=false(the default), even though those URLs cannot be reconstructed from the package name, version, and registry #11407.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Fix too many open files error sometimes happening on Windows, when creating command shims in
- 11.0.230 Apr 2026
Release notes
Open source →Patch Changes
- Fix
ENOENTsymlink failure whenpnpm add -gtriggers the approve-builds prompt. The global add flow used to forward an absolutemodulesDir(<installDir>/node_modules) into the install run byapprove-builds. The install layer treatedmodulesDiras a path relative tolockfileDirand joined it again, producing a doubled path on Windows becausepath.joindoes not collapse an embedded absolute path. The hoist step then tried tomkdirand symlink under<installDir>\<installDir>\node_modules\.pnpm\node_modules\...and failed withENOENT#11403. - Fixed
packageManagerDependenciesgoing stale when pnpm is invoked through corepack. The lockfile sync (and thedevEngines.packageManagerversion check) previously ran only when pnpm was invoked directly; under corepack the entire block was skipped, so a stale entry would persist even after the running pnpm version changed. The lockfile sync now runs regardless of how pnpm was invoked, while the pnpm-managed version switch (onFail: 'download') remains skipped under corepack so it doesn't fight corepack's own version selection #11397. - Fix recursive publish summaries to report the manifest from
publishConfig.directorywhen packages publish from a generated directory #11239. - Fix negated
os/cpuentries (e.g.["!win32"]) being incorrectly rejected whensupportedArchitecturesexpands to multiple platforms #11375.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Fix
- 11.0.129 Apr 2026
Release notes
Open source →Patch Changes
- Report unknown top-level options before falling back to implicit
pnpm runscripts. - Reject
nullnamed catalogs in workspace manifests withInvalidWorkspaceManifestErrorinstead of crashing with a rawTypeError. - Populate download location for git-sourced dependencies in SBOM output. Previously
pnpm sbomemittedNOASSERTION(SPDX) and omitted the distribution reference (CycloneDX) for git dependencies. Now emits the git URL with commit hash, e.g.git+https://github.com/user/repo.git#commit. pnpm self-updatenow keepspackage.json'spackageManageranddevEngines.packageManagerin sync. When the legacypackageManagerfield pins pnpm, both fields are rewritten to the new exact pnpm version on update —packageManagertopnpm@<version>(without an integrity hash), anddevEngines.packageManager.versionto the same exact<version>(dropping any range operator). When onlydevEngines.packageManageris declared, the existing range-preserving behavior is unchanged #11388.- Sort the keys of the overrides object returned by
pnpm audit --fixso that the log output order matches the order written topnpm-workspace.yaml. - Update the env lockfile's
packageManagerDependenciesentry whendevEngines.packageManagerdeclares a pnpm version that the lockfile no longer satisfies. Previously, the stale entry was kept even though the running pnpm matched the declared version, silently breaking the integrity record #11387.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Report unknown top-level options before falling back to implicit
- 11.0.028 Apr 2026
Release notes
Open source →Migration guide: Migrating from v10 to v11
Highlights
Major
- Node.js 22+ required — support for Node 18, 19, 20, and 21 is dropped, pnpm itself is now pure ESM, and the standalone exe requires glibc 2.27.
- Supply-chain protection on by default —
minimumReleaseAgedefaults to 1 day (newly published packages are not resolved for 24h) andblockExoticSubdepsdefaults totrue. allowBuildsreplaces the old build-dependency settings —onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies,ignoredBuiltDependencies, andignoreDepScriptshave been removed.- Global installs are isolated and use the global virtual store by default — each
pnpm add -ggets its own directory with its ownpackage.json,node_modules, and lockfile. - New SQLite-backed store index (store v11) with bundled manifests and hex digests, reducing filesystem syscalls and speeding up installation.
- Native publish flow —
pnpm publish,login,logout,view,deprecate,unpublish,dist-tag, andversionno longer delegate to the npm CLI, and the remaining npm passthrough commands now throw "not implemented". pnpm audituses npm's bulk advisories endpoint — the legacy/security/auditsendpoints are gone. CVE-based filtering has been replaced with GHSA-based filtering: migrateauditConfig.ignoreCvesentries toauditConfig.ignoreGhsas..npmrcis auth/registry only — all other settings must live inpnpm-workspace.yamlor the new globalconfig.yaml, and environment variables use thepnpm_config_*prefix.- Runtime installs are slimmer — installing a Node.js runtime via
node@runtime:<version>no longer extracts the bundlednpm,npx, andcorepack, roughly halving the files pnpm has to hash, write, and link.
Minor
- New commands:
pnpm ci,pnpm sbom,pnpm clean,pnpm peers check,pnpm runtime set,pnpm docs/home,pnpm ping,pnpm search,pnpm star/unstar/stars,pnpm whoami,pnpm with, andpnpm pack-app, pluspn/pnxshort aliases. - ESM pnpmfiles via
.pnpmfile.mjs, which takes priority over.pnpmfile.cjswhen present. pnpm audit --fix=updatefixes vulnerabilities by updating packages in the lockfile instead of adding overrides, andpnpm audit --fix --interactivelets you select which advisories to fix.pnpm pack-apppacks a CommonJS entry into a standalone executable for one or more target platforms using Node.js Single Executable Applications.- Faster HTTP and I/O — undici with Happy Eyeballs, direct-to-CAS writes, skipped staging directory, pre-allocated tarball downloads, and an NDJSON metadata cache.
Major Changes
Requirements
- pnpm is now distributed as pure ESM.
- Dropped support for Node.js v18, 19, 20, and 21.
- The standalone exe version of pnpm requires at least glibc 2.27.
Security & Build Defaults
-
Changed default values:
optimisticRepeatInstallis nowtrue,verifyDepsBeforeRunis nowinstall,minimumReleaseAgeis now1440(1 day), andminimumReleaseAgeStrictisfalse. Newly published packages will not be resolved until they are at least 1 day old. This protects against supply chain attacks by giving the community time to detect and remove compromised versions. To opt out, setminimumReleaseAge: 0inpnpm-workspace.yaml#11158. -
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Removed deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies,ignoredBuiltDependencies, andignoreDepScripts#11220.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed
allowNonAppliedPatchesin favor ofallowUnusedPatches. -
Removed
ignorePatchFailures; patch application failures now throw an error.
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- The bundled manifest (name, version, bin, engines, scripts, etc.) is now stored directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - The package index in the content-addressable store is now backed by SQLite. Instead of individual JSON files under
$STORE/index/, package metadata is stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
-
Globally installed binaries are now stored in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
Configuration
-
pnpm no longer reads all settings from
.npmrc. Only auth and registry settings are read from.npmrcfiles. All other settings (likehoistPattern,nodeLinker,shamefullyHoist, etc.) must be configured inpnpm-workspace.yamlor the global~/.config/pnpm/config.yaml#11189. -
Network settings (
httpProxy,httpsProxy,noProxy,localAddress,strictSsl,gitShallowHosts) are now written toconfig.yaml(global) orpnpm-workspace.yaml(local) instead of.npmrc/auth.ini. They are still readable from.npmrcfor easier migration from the npm CLI #11209.pnpm no longer reads
npm_config_*environment variables. Usepnpm_config_*environment variables instead (e.g.,pnpm_config_registryinstead ofnpm_config_registry).pnpm no longer reads the npm global config at
$PREFIX/etc/npmrc.pnpm loginwrites auth tokens to~/.config/pnpm/auth.ini.New
registriessetting inpnpm-workspace.yaml:registries: default: https://registry.npmjs.org/ "@my-org": https://private.example.com/ "@internal": https://nexus.corp.com/Auth tokens in
~/.npmrcstill work — pnpm continues to read~/.npmrcas a fallback for registry authentication. The newnpmrcAuthFilesetting can be used to point to a different file instead of~/.npmrc. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigslooks something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
pnpm config get(without--json) no longer prints INI formatted text. Instead, it prints JSON for objects and arrays, and raw strings for strings, numbers, booleans, and nulls.pnpm config get --jsonstill prints all types of values as JSON, as before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: keys that start with@or//are preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non-camelCase options from the workspace manifest (pnpm-workspace.yaml).
Removed Commands & npm Passthrough
-
pnpm no longer falls back to the npm CLI. Commands that were previously passed through to npm (
access,bugs,docs,edit,find,home,issues,owner,ping,prefix,profile,pkg,repo,search,set-script,star,stars,team,token,unstar,whoami,xmas) and their aliases (s,se) now throw a "not implemented" error, with a suggestion to use the npm CLI directly #10642. Other previously passed-through commands —view(info,show,v),login(adduser),logout,deprecate,unpublish,dist-tag, andversion— have been reimplemented natively in pnpm (see New Commands below). -
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile.
Lifecycle Scripts
- pnpm no longer populates
npm_config_*environment variables from the pnpm config during lifecycle scripts. Only well-knownnpm_*env vars are now set, matching Yarn's behavior #11116.
CLI Output
- Cleaner output for script execution: pnpm now prints
$ commandinstead of> pkg@version stage path\n> command, and shows project name and path only when running in a different directory. The$ commandline is printed to stderr to keep stdout clean for piping #11132. - During install, instead of rendering the full peer dependency issues tree, pnpm now suggests running
pnpm peers checkto view the issues #11133.
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Added support for lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using the
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
The root workspace project is no longer excluded when it is explicitly selected via a filter #10465.
Audit
-
pnpm auditnow calls npm's/-/npm/v1/security/advisories/bulkendpoint. The legacy/-/npm/v1/security/audits{,/quick}endpoints have been retired by the registry, so the legacy request/response contract is no longer supported.The bulk endpoint does not return CVE identifiers. CVE-based filtering has been replaced with GitHub advisory ID (GHSA) filtering:
auditConfig.ignoreCves→auditConfig.ignoreGhsas(the previous key is no longer recognized)pnpm audit --ignore <id>/pnpm audit --ignore-unfixablenow read and write GHSAs instead of CVEs- GHSAs are derived from each advisory's
url(https://github.com/advisories/GHSA-xxxx-xxxx-xxxx)
To migrate: replace each
CVE-YYYY-NNNNNentry in yourauditConfig.ignoreCveswith the correspondingGHSA-xxxx-xxxx-xxxxvalue (visible in theMore infocolumn ofpnpm auditoutput) and move it underauditConfig.ignoreGhsas.
Package Manager Settings
-
Breaking: removed the
managePackageManagerVersions,packageManagerStrict, andpackageManagerStrictVersionsettings. They existed only to derive theonFailbehavior for the legacypackageManagerfield, and thepmOnFailsetting introduced alongsidepnpm withsubsumes all three — it directly sets theonFailbehavior of bothpackageManageranddevEngines.packageManager. TheCOREPACK_ENABLE_STRICTenvironment variable is no longer honored (it only gatedpackageManagerStrict); usepmOnFailinstead.Migration:
Removed setting Replace with managePackageManagerVersions: truepmOnFail: download(default)managePackageManagerVersions: falsepmOnFail: ignorepackageManagerStrict: falsepmOnFail: warnpackageManagerStrictVersion: truepmOnFail: errorCOREPACK_ENABLE_STRICT=0pmOnFail: warn
Runtime Installs
- Installing a Node.js runtime via
node@runtime:<version>(includingpnpm env useandpnpm runtime set node) no longer extracts the bundlednpm,npx, andcorepackfrom the Node.js archive. This cuts roughly half of the files pnpm has to hash, write to the CAS, and link during installation, making runtime installs noticeably faster. Users who still neednpmcan install it as a separate package.
Minor Changes
New Commands
- Added native
pnpm view(info,show,v) command for viewing package metadata from the registry #11064. - Added
pnpm login(andpnpm adduseralias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #11094. - Added
pnpm logoutcommand for logging out of npm registries. Revokes the authentication token on the registry and removes it from the local auth config file #11213. - Added native
pnpm deprecateandpnpm undeprecatecommands for setting and removing deprecation messages on package versions without delegating to the npm CLI #11120. - Added native
pnpm unpublishcommand. Supports unpublishing specific versions, version ranges via semver, and entire packages with--force#11128. - Added native
pnpm dist-tagcommand (ls,add,rmsubcommands) #11218. - Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Added the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879. pnpm audit --fixnow supports a new interactive mode via--interactive/-i.- Added the
pnpm docscommand and its aliaspnpm home. This command opens the package documentation or homepage in the browser. When the package has no valid homepage, it falls back tohttps://npmx.dev/package/<name>. - Added native
pnpm pingcommand to test registry connectivity. Provides a simple way to verify connectivity to the configured registry without requiring external tools. - Implemented native
searchcommand and its aliases (s,se,find). - Implemented native
star,unstar,stars, andwhoamicommands. - Add
pnpm with <version|current> <args...>command. Runs pnpm at a specific version (or the currently active one) for a single invocation, bypassing the project'spackageManageranddevEngines.packageManagerpins. - Added a new
pnpm pack-appcommand that packs a CommonJS entry file into a standalone executable for one or more target platforms, using the Node.js Single Executable Applications API under the hood.
Configuration
-
Added support for a global YAML config file named
config.yaml.Configuration is now split into two categories:
- Registry and auth settings, which can be stored in INI files such as the global
rcfile and local.npmrc. - pnpm-specific settings, which can only be loaded from YAML files such as the global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings, which can be stored in INI files such as the global
-
Added support for loading environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not CLI arguments. -
Added support for reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Added support for specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. Config dependency and package manager integrity info is now stored inpnpm-lock.yamlinstead of inlined inpnpm-workspace.yaml: the workspace manifest contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964. -
Added
nodeDownloadMirrorssetting to configure custom Node.js download mirrors inpnpm-workspace.yaml. This replaces thenode-mirror:<channel>.npmrcsetting, which is no longer read #11194:nodeDownloadMirrors: release: https://my-mirror.example.com/download/release/ -
pnpm dlxandpnpm createnow respect security and trust policy settings (minimumReleaseAge,minimumReleaseAgeExclude,minimumReleaseAgeStrict,trustPolicy,trustPolicyExclude,trustPolicyIgnoreAfter) from project-level configuration #11183. -
pnpm initnow writes adevEngines.packageManagerfield instead of thepackageManagerfield wheninit-package-manageris enabled. -
Added a new setting
runtimeOnFailthat overrides theonFailfield ofdevEngines.runtime(andengines.runtime) in the root project'spackage.json. Accepted values:ignore,warn,error,download. For example, settingruntimeOnFail=downloadmakes pnpm download the declared runtime version even when the manifest does not setonFail: "download". -
Added a new setting
minimumReleaseAgeIgnoreMissingTime, which istrueby default. When enabled, pnpm skips theminimumReleaseAgematurity check if the registry metadata does not include thetimefield. Set tofalseto fail resolution instead.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM, using the
.mjsextension. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded #9730.
CLI & Other
- The built-in
clean,setup,deploy, andrebuildcommands now prefer user scripts over built-in commands. When a project'spackage.jsonhas a script with the same name,pnpmexecutes the script instead of the built-in command. Addedpurgeas an alias for the built-incleancommand, which always runs the built-in regardless of scripts #11118. - Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. pnpm approve-buildsnow accepts positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030.- During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.pnpm audit --fixnow adds the minimum patched version for each advisory tominimumReleaseAgeExcludeinpnpm-workspace.yaml, so the security fix can be installed without waiting forminimumReleaseAge#11216.- pnpm now warns when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Replaced
node-fetchwith nativeundicifor HTTP requests throughout pnpm #10537. - Eliminated redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Eliminated the staging directory when importing packages into
node_modules, avoiding the overhead of creating a temp dir and renaming per package #11088. - CAS files are now written directly to their final content-addressed path instead of to a temp file and renamed. This eliminates ~30k rename syscalls per cold install #11087.
- Optimized hot-path string operations in the content-addressable store and increased
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086. - Improved HTTP performance with Happy Eyeballs (dual-stack), better keep-alive settings, and an optimized global dispatcher. Tarball downloads with known size now pre-allocate memory to avoid double-copy overhead #11151.
- Adopted
If-Modified-Sincefor conditional metadata fetches, avoiding re-downloading unchanged registry metadata #11161. - Switched to abbreviated metadata when checking
minimumReleaseAge, reducing the amount of data fetched from the registry #11160. - Switched the metadata cache to NDJSON format, improving read/write performance #11188.
Patch Changes
-
Switched to
process.stderr.writeinstead ofconsole.errorfor script logging #11140. -
Respected the
frozen-lockfileflag when migrating config dependencies #11067. -
Removed the
--workspaceflag from theversioncommand #11115. -
Handled
ENOTSUPerror in the clone import path during parallel I/O #11117. -
Fixed
pnpm auditcommand. -
Updated dependencies to fix vulnerabilities.
-
pnpm now checks whether a package is installable for non-npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
pnpm now explicitly passes the path of the global
rcconfig file tonpm. -
Fixed YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is now written toallowBuilds. -
Fixed a bug in which specifying
filterinpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Deferred patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
pnpm now fails on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043. -
Fixed a crash in the lockfile merger when merging non-semver version strings (e.g.
link:,file:, git URLs) #11102. -
Handled
ENOTSUPerror inlinkOrCopyduring parallel imports #11103. -
Skipped linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #11069.
-
Fixed
_passwordhandling for the default registry to decode from base64 before use, consistent with scoped registry behavior #11089. -
Fixed a bug where the CAS locker cache was not updated when a file already existed with correct integrity #11085.
-
Prevented catalog entries from being removed by
cleanupUnusedCatalogswhen they are referenced only from workspaceoverrides#11075. -
Resolved patch file paths during
pnpm fetch#11054. -
Fixed invalid specifiers for peers on all non-exact version selectors #11049.
-
Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #11000.
-
Prepended
Bearerto the authorization token generated bytokenHelperif it is missing, aligning with npm's behavior #11097. -
Propagated error cause when throwing
PnpmErrorin@pnpm/npm-resolver#10990. -
Fixed SQLite race condition during store initialization on Windows.
-
Removed
rimrafSyncinimportIndexedDirfast-path error handler #11168. -
Fixed
pnpm dedupe --checkunexpectedly failing due to non-deterministic resolution #11110. -
Fixed empty files not being rejected in
isEmptyDirOrNothing#11182. -
Fixed
.bat/.cmdtoken helpers not working on Windows due to missingshell: trueoption.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-rc.521 Apr 2026pre-release
Release notes
Open source →Patch Changes
-
Fix the
@pnpm/exeSEA executable crashing at startup on Node.js v25.7+. Two separate regressions in@pnpm/[email protected]are addressed:-
pnpm pack-appnow pins the Node.js used to write the SEA blob to the exact embedded runtime version. The SEA blob format changed in Node.js v25.7 (ESM entry-point support added aModuleFormatheader byte), so a blob produced by a pre-25.7 builder cannot be deserialized by a 25.7+ runtime and vice versa. In rc.4 the CI host Node.js (v25.6.1) built blobs embedded in a v25.9.0 runtime, trippingSeaDeserializer::Read() ... format_value <= kModuleon every invocation.pack-appnow downloads a host-arch builder Node.js of the target version when the running Node.js doesn't already match. -
The pnpm CJS SEA entry shim now loads
dist/pnpm.mjsthroughModule.createRequire(process.execPath)instead ofawait import(pathToFileURL(...).href). In Node.js v25.7+, the ambientrequireandimport()inside a CJS SEA entry are replaced with embedder hooks that only resolve built-in module names, causing externalfile://loads to fail withERR_UNKNOWN_BUILTIN_MODULE. An explicitcreateRequire()bypasses those hooks.
-
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.0-rc.421 Apr 2026pre-release
Release notes
Open source →Major Changes
- Installing a Node.js runtime via
node@runtime:<version>(includingpnpm env useandpnpm runtime set node) no longer extracts the bundlednpm,npx, andcorepackfrom the Node.js archive. This cuts roughly half of the files pnpm has to hash, write to the CAS, and link during installation, making runtime installs noticeably faster. Users who still neednpmcan install it as a separate package.
Minor Changes
-
pnpm pack-app: replaced the--node-versionflag with--runtime, which takes a<name>@<version>spec (e.g.--runtime [email protected]). The correspondingpnpm.app.nodeVersionkey in package.json was renamed topnpm.app.runtimewith the same syntax. Onlynodeis supported today; the prefix leaves room for future runtimes (bun,deno).The previous
--node-versionflag silently inherited from pnpm's globalnode-versionrc setting (which controls which Node runs user scripts), causing the wrong Node build to be embedded in SEAs for users who had that rc key set.
Patch Changes
- Restored the legacy
@pnpm/{macos,win,linux,linuxstatic}-{x64,arm64}npm names for the platform-specific optional dependencies of@pnpm/exe, reverting the scope-nested@pnpm/exe.<platform>-<arch>[-musl]rename from #11316 on the published package names only — the workspace directory layout (pnpm/artifacts/<platform>-<arch>[-musl]/) and the GitHub release asset filenames stay on the new scheme. The rename brokepnpm self-updatefrom v10, which looks up the platform child by its legacy name.linkExePlatformBinarynow checks for both schemes so a later rename can ship without a v10-compatibility hazard.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Installing a Node.js runtime via
- 11.0.0-rc.320 Apr 2026pre-release
Release notes
Open source →Minor Changes
-
Added a new
pnpm pack-appcommand that packs a CommonJS entry file into a standalone executable for one or more target platforms, using the Node.js Single Executable Applications API under the hood. Targets are specified as<os>-<arch>[-<libc>](e.g.linux-x64,linux-x64-musl,macos-arm64,win-x64) and each produces an executable underdist-app/<target>/by default. Requires Node.js v25.5+ to perform the injection; an older host downloads Node.js v25 automatically. -
pnpm audit --fixnow respects theauditLevelsetting and supports a new interactive mode via--interactive/-i. Previously,pnpm audit --fixwould fix all vulnerabilities regardless of the configuredauditLevel, whilepnpm audit(without--fix) correctly filtered by severity. Now both commands consistently filter advisories by theauditLevelsetting, and you can usepnpm audit --fix -ito review and select which vulnerabilities to fix interactively.Overrides emitted by
pnpm audit --fixnow use a caret range (^X.Y.Z) instead of an open-ended>=X.Y.Z, so applying a security fix can no longer silently promote a dependency across a major version boundary. -
Added a new setting
minimumReleaseAgeIgnoreMissingTime, which istrueby default. When enabled, pnpm skips theminimumReleaseAgematurity check if the registry metadata does not include thetimefield. Set tofalseto fail resolution instead. -
Fixed and expanded
pnpm versionto match npm behavior:- Accept an explicit semver version (e.g.
pnpm version 1.2.3) in addition to bump types. - Recognize
--no-commit-hooks,--no-git-tag-version,--sign-git-tag, and--message. - Fix
--no-git-checkswhich was previously parsed incorrectly. - Create a git commit and annotated tag for the version bump when running inside a git repository (unless
--no-git-tag-versionis used).--messagesupports%sreplacement with the new version, and--tag-version-prefixcontrols the tag prefix (defaults tov). Git commits and tags are always skipped in recursive mode since multiple packages may be bumped to different versions in a single run #11271.
- Accept an explicit semver version (e.g.
-
Renamed the platform-specific optional dependencies of
@pnpm/exeto the new@pnpm/exe.<platform>-<arch>[-<libc>]scheme, usingprocess.platformvalues (linux,darwin,win32) for the OS segment. The umbrella package@pnpm/exeitself is unchanged so existingnpm i -g @pnpm/exeandpnpm self-updateflows keep working.before after @pnpm/linux-x64@pnpm/exe.linux-x64@pnpm/linux-arm64@pnpm/exe.linux-arm64@pnpm/linuxstatic-x64@pnpm/exe.linux-x64-musl@pnpm/linuxstatic-arm64@pnpm/exe.linux-arm64-musl@pnpm/macos-x64@pnpm/exe.darwin-x64@pnpm/macos-arm64@pnpm/exe.darwin-arm64@pnpm/win-x64@pnpm/exe.win32-x64@pnpm/win-arm64@pnpm/exe.win32-arm64GitHub release asset filenames follow the same scheme —
pnpm-linuxstatic-x64.tar.gzbecomespnpm-linux-x64-musl.tar.gz,pnpm-macos-*becomespnpm-darwin-*,pnpm-win-*becomespnpm-win32-*. Anyone downloading releases directly needs to use the new filenames;get.pnpm.io/install.shandinstall.ps1will be updated in lockstep to accept both schemes based on the requested version.Resolves #11314.
Patch Changes
- Do not print the
Cannot use both "packageManager" and "devEngines.packageManager" in package.json. "packageManager" will be ignoredwarning when the two fields specify the exact same package manager name and version string. This lets projects keep both fields during the migration frompackageManagertodevEngines.packageManagerwithout a noisy warning #11301. - Fix installing a directory dependency (
file:<dir>) from an absolute path on a different drive on Windows. The directory fetcher was joining the stored directory ontolockfileDir, which on Windows concatenates an absolute cross-drive path literally (path.join('D:\\...', 'C:\\Users\\...')→'D:\\...\\C:\\Users\\...'). Usepath.resolveso absolute paths are respected. This surfaced as an ENOENT duringpnpm setupin CI whenPNPM_HOMEand the OS temp directory were on different drives. - Fixed
pnpm sbomandpnpm licensesfailing to resolve license information for git-sourced dependencies (git+https://,git+ssh://,github:shorthand). These commands now correctly read the package manifest from the content-addressable store fortype: 'git'resolutions #11260. - Fix
ERR_PNPM_OUTDATED_LOCKFILEwhen approving builds during a global install. Theapprove-buildsflow called bypnpm add -gpassed the global packages directory to the subsequent install asworkspaceDir, which caused sibling install directories (such as those left behind bypnpm self-update) to be picked up as workspace projects and fail the frozen-lockfile check. - Restore the peer suffix encoding used by pnpm 10 for linked dependency paths. A
filenamifyupgrade changed how leading./and../segments were normalized, producing peer suffixes like(b@+packages+b)instead of(b@packages+b)for linked packages outside the workspace root, causing lockfile churn #11272. - Fix: different platform variants of the same runtime (e.g.
node@runtime:25.9.0glibc vs. musl) no longer share a single global-virtual-store entry. The virtual store path now incorporates the selected variant's integrity, so installs with different--os/--cpu/--libcend up in separate directories andpnpm add --libc=musl node@runtime:<v>reliably fetches the musl binary even when the glibc variant is already cached. pnpm sbomnow detects licenses declared via the deprecatedlicensesarray inpackage.json(e.g.busboy,streamsearch,limiter) and falls back to scanning on-diskLICENSEfiles — mirroring the resolution logic ofpnpm licenses. Previously these packages were reported asNOASSERTION. Shared license resolution (manifest parsing + LICENSE-file fallback) lives in the new@pnpm/deps.compliance.license-resolverpackage. When a manifest sets bothlicenseandlicenses, the modernlicensefield now takes precedence for both commands (previouslypnpm licensespreferredlicenses) #11248.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.0-rc.217 Apr 2026pre-release
Release notes
Open source →Major Changes
-
Breaking: removed the
managePackageManagerVersions,packageManagerStrict, andpackageManagerStrictVersionsettings. They existed only to derive theonFailbehavior for the legacypackageManagerfield, and thepmOnFailsetting introduced alongsidepnpm withsubsumes all three — it directly sets theonFailbehavior of bothpackageManageranddevEngines.packageManager. TheCOREPACK_ENABLE_STRICTenvironment variable is no longer honored (it only gatedpackageManagerStrict); usepmOnFailinstead.Migration:
Removed setting Replace with managePackageManagerVersions: truepmOnFail: download(default)managePackageManagerVersions: falsepmOnFail: ignorepackageManagerStrict: falsepmOnFail: warnpackageManagerStrictVersion: truepmOnFail: errorCOREPACK_ENABLE_STRICT=0pmOnFail: warn
Minor Changes
-
pnpm dlxandpnpm createnow respect security and trust policy settings (minimumReleaseAge,minimumReleaseAgeExclude,minimumReleaseAgeStrict,trustPolicy,trustPolicyExclude,trustPolicyIgnoreAfter) from project-level configuration #11183. -
Implemented native
star,unstar,stars, andwhoamicommands. -
Add
pnpm with <version|current> <args...>command. Runs pnpm at a specific version (or the currently active one) for a single invocation, bypassing the project'spackageManageranddevEngines.packageManagerpins. Uses the same install mechanism aspnpm self-update, caching the downloaded pnpm in the global virtual store for reuse.Examples:
pnpm with current install # ignore the pinned version, use the running pnpm pnpm with 11.0.0-rc.1 install # install using pnpm 11.0.0-rc.1 pnpm with next install # install using the "next" dist-tagAlso adds a new
pmOnFailsetting that overrides theonFailbehavior ofpackageManageranddevEngines.packageManager. Accepted values:download,error,warn,ignore. Can be set via CLI flag, env var,pnpm-workspace.yaml, or.npmrc— useful when version management is handled by an external tool (asdf, mise, Volta, etc.) and the project wants pnpm itself to skip the check.pnpm install --pm-on-fail=ignore # direct CLI flag pnpm_config_pm_on_fail=ignore pnpm install # env var # or in pnpm-workspace.yaml: # pmOnFail: ignore -
pnpm initnow writes adevEngines.packageManagerfield instead of thepackageManagerfield wheninit-package-manageris enabled. -
When pnpm is declared via the
packageManagerfield inpackage.json, its resolution info is no longer written topnpm-lock.yaml— unless the pinned pnpm version is v12 or newer. ThepackageManagerDependenciessection is still populated (and reused across runs) when pnpm is declared viadevEngines.packageManager. This makes the transition from pnpm v10 to v11 quieter by avoiding unnecessary lockfile churn for projects that pin an older pnpm in the legacypackageManagerfield. -
Added a new setting
runtimeOnFailthat overrides theonFailfield ofdevEngines.runtime(andengines.runtime) in the root project'spackage.json. Accepted values:ignore,warn,error,download. For example, settingruntimeOnFail=downloadmakes pnpm download the declared runtime version even when the manifest does not setonFail: "download".
Patch Changes
pnpm initno longer adds thedevEngines.packageManagerfield when run inside a workspace subpackage. The field is only added to the workspace root'spackage.json.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.0-rc.115 Apr 2026pre-release
Release notes
Open source →Major Changes
-
pnpm auditnow calls npm's/-/npm/v1/security/advisories/bulkendpoint. The legacy/-/npm/v1/security/audits{,/quick}endpoints have been retired by the registry, so the legacy request/response contract is no longer supported.The bulk endpoint does not return CVE identifiers. CVE-based filtering has been replaced with GitHub advisory ID (GHSA) filtering:
auditConfig.ignoreCves→auditConfig.ignoreGhsas(the previous key is no longer recognized)pnpm audit --ignore <id>/pnpm audit --ignore-unfixablenow read and write GHSAs instead of CVEs- GHSAs are derived from each advisory's
url(https://github.com/advisories/GHSA-xxxx-xxxx-xxxx)
To migrate: replace each
CVE-YYYY-NNNNNentry in yourauditConfig.ignoreCveswith the correspondingGHSA-xxxx-xxxx-xxxxvalue (visible in theMore infocolumn ofpnpm auditoutput) and move it underauditConfig.ignoreGhsas.
Minor Changes
- Added the
pnpm docscommand and its aliaspnpm home. This command opens the package documentation or homepage in the browser. When the package has no valid homepage, it falls back tohttps://npmx.dev/package/<name>. - Added native
pnpm pingcommand to test registry connectivity. Provides a simple way to verify connectivity to the configured registry without requiring external tools. - Implemented native
searchcommand and its aliases (s,se,find).
Patch Changes
- Fixed
pnpm store pruneremoving packages used by the globally installed pnpm, breaking it.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
-
- 11.0.0-rc.010 Apr 2026pre-release
Release notes
Open source →Highlights
Major
- Node.js 22+ required — support for Node 18, 19, 20, and 21 is dropped, pnpm itself is now pure ESM, and the standalone exe requires glibc 2.27.
- Supply-chain protection on by default —
minimumReleaseAgedefaults to 1 day (newly published packages are not resolved for 24h) andblockExoticSubdepsdefaults totrue. allowBuildsreplaces the old build-dependency settings —onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies,ignoredBuiltDependencies, andignoreDepScriptshave been removed.- Global installs are isolated and use the global virtual store by default — each
pnpm add -ggets its own directory with its ownpackage.json,node_modules, and lockfile. - New SQLite-backed store index (store v11) with bundled manifests and hex digests, reducing filesystem syscalls and speeding up installation.
- Native publish flow —
pnpm publish,login,logout,view,deprecate,unpublish,dist-tag, andversionno longer delegate to the npm CLI, and the remaining npm passthrough commands now throw "not implemented". .npmrcis auth/registry only — all other settings must live inpnpm-workspace.yamlor the new globalconfig.yaml, and environment variables use thepnpm_config_*prefix.
Minor
- New commands:
pnpm ci,pnpm sbom,pnpm clean,pnpm peers check, andpnpm runtime set, pluspn/pnxshort aliases. - ESM pnpmfiles via
.pnpmfile.mjs, which takes priority over.pnpmfile.cjswhen present. pnpm audit --fix=updatefixes vulnerabilities by updating packages in the lockfile instead of adding overrides.- Faster HTTP and I/O — undici with Happy Eyeballs, direct-to-CAS writes, skipped staging directory, pre-allocated tarball downloads, and an NDJSON metadata cache.
Major Changes
Requirements
- pnpm is now distributed as pure ESM.
- Dropped support for Node.js v18, 19, 20, and 21.
- The standalone exe version of pnpm requires at least glibc 2.27.
Security & Build Defaults
-
Changed default values:
optimisticRepeatInstallis nowtrue,verifyDepsBeforeRunis nowinstall,minimumReleaseAgeis now1440(1 day), andminimumReleaseAgeStrictisfalse. Newly published packages will not be resolved until they are at least 1 day old. This protects against supply chain attacks by giving the community time to detect and remove compromised versions. To opt out, setminimumReleaseAge: 0inpnpm-workspace.yaml#11158. -
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Removed deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies,ignoredBuiltDependencies, andignoreDepScripts#11220.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed
allowNonAppliedPatchesin favor ofallowUnusedPatches. -
Removed
ignorePatchFailures; patch application failures now throw an error.
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- The bundled manifest (name, version, bin, engines, scripts, etc.) is now stored directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - The package index in the content-addressable store is now backed by SQLite. Instead of individual JSON files under
$STORE/index/, package metadata is stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
-
Globally installed binaries are now stored in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
Configuration
-
pnpm no longer reads all settings from
.npmrc. Only auth and registry settings are read from.npmrcfiles. All other settings (likehoistPattern,nodeLinker,shamefullyHoist, etc.) must be configured inpnpm-workspace.yamlor the global~/.config/pnpm/config.yaml#11189. -
Network settings (
httpProxy,httpsProxy,noProxy,localAddress,strictSsl,gitShallowHosts) are now written toconfig.yaml(global) orpnpm-workspace.yaml(local) instead of.npmrc/auth.ini. They are still readable from.npmrcfor easier migration from the npm CLI #11209.pnpm no longer reads
npm_config_*environment variables. Usepnpm_config_*environment variables instead (e.g.,pnpm_config_registryinstead ofnpm_config_registry).pnpm no longer reads the npm global config at
$PREFIX/etc/npmrc.pnpm loginwrites auth tokens to~/.config/pnpm/auth.ini.New
registriessetting inpnpm-workspace.yaml:registries: default: https://registry.npmjs.org/ "@my-org": https://private.example.com/ "@internal": https://nexus.corp.com/Auth tokens in
~/.npmrcstill work — pnpm continues to read~/.npmrcas a fallback for registry authentication. The newnpmrcAuthFilesetting can be used to point to a different file instead of~/.npmrc. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigslooks something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
pnpm config get(without--json) no longer prints INI formatted text. Instead, it prints JSON for objects and arrays, and raw strings for strings, numbers, booleans, and nulls.pnpm config get --jsonstill prints all types of values as JSON, as before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: keys that start with@or//are preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non-camelCase options from the workspace manifest (pnpm-workspace.yaml).
Removed Commands & npm Passthrough
-
pnpm no longer falls back to the npm CLI. Commands that were previously passed through to npm (
access,bugs,docs,edit,find,home,issues,owner,ping,prefix,profile,pkg,repo,search,set-script,star,stars,team,token,unstar,whoami,xmas) and their aliases (s,se) now throw a "not implemented" error, with a suggestion to use the npm CLI directly #10642. Other previously passed-through commands —view(info,show,v),login(adduser),logout,deprecate,unpublish,dist-tag, andversion— have been reimplemented natively in pnpm (see New Commands below). -
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile.
Lifecycle Scripts
- pnpm no longer populates
npm_config_*environment variables from the pnpm config during lifecycle scripts. Only well-knownnpm_*env vars are now set, matching Yarn's behavior #11116.
CLI Output
- Cleaner output for script execution: pnpm now prints
$ commandinstead of> pkg@version stage path\n> command, and shows project name and path only when running in a different directory. The$ commandline is printed to stderr to keep stdout clean for piping #11132. - During install, instead of rendering the full peer dependency issues tree, pnpm now suggests running
pnpm peers checkto view the issues #11133.
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Added support for lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using the
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
The root workspace project is no longer excluded when it is explicitly selected via a filter #10465.
Minor Changes
New Commands
- Added native
pnpm view(info,show,v) command for viewing package metadata from the registry #11064. - Added
pnpm login(andpnpm adduseralias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #11094. - Added
pnpm logoutcommand for logging out of npm registries. Revokes the authentication token on the registry and removes it from the local auth config file #11213. - Added native
pnpm deprecateandpnpm undeprecatecommands for setting and removing deprecation messages on package versions without delegating to the npm CLI #11120. - Added native
pnpm unpublishcommand. Supports unpublishing specific versions, version ranges via semver, and entire packages with--force#11128. - Added native
pnpm dist-tagcommand (ls,add,rmsubcommands) #11218. - Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Added the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879.
Configuration
-
Added support for a global YAML config file named
config.yaml.Configuration is now split into two categories:
- Registry and auth settings, which can be stored in INI files such as the global
rcfile and local.npmrc. - pnpm-specific settings, which can only be loaded from YAML files such as the global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings, which can be stored in INI files such as the global
-
Added support for loading environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not CLI arguments. -
Added support for reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Added support for specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. Config dependency and package manager integrity info is now stored inpnpm-lock.yamlinstead of inlined inpnpm-workspace.yaml: the workspace manifest contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964. -
Added
nodeDownloadMirrorssetting to configure custom Node.js download mirrors inpnpm-workspace.yaml. This replaces thenode-mirror:<channel>.npmrcsetting, which is no longer read #11194:nodeDownloadMirrors: release: https://my-mirror.example.com/download/release/
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM, using the
.mjsextension. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded #9730.
CLI & Other
- The built-in
clean,setup,deploy, andrebuildcommands now prefer user scripts over built-in commands. When a project'spackage.jsonhas a script with the same name,pnpmexecutes the script instead of the built-in command. Addedpurgeas an alias for the built-incleancommand, which always runs the built-in regardless of scripts #11118. - Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. pnpm approve-buildsnow accepts positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030.- During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.pnpm audit --fixnow adds the minimum patched version for each advisory tominimumReleaseAgeExcludeinpnpm-workspace.yaml, so the security fix can be installed without waiting forminimumReleaseAge#11216.- pnpm now warns when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Replaced
node-fetchwith nativeundicifor HTTP requests throughout pnpm #10537. - Eliminated redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Eliminated the staging directory when importing packages into
node_modules, avoiding the overhead of creating a temp dir and renaming per package #11088. - CAS files are now written directly to their final content-addressed path instead of to a temp file and renamed. This eliminates ~30k rename syscalls per cold install #11087.
- Optimized hot-path string operations in the content-addressable store and increased
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086. - Improved HTTP performance with Happy Eyeballs (dual-stack), better keep-alive settings, and an optimized global dispatcher. Tarball downloads with known size now pre-allocate memory to avoid double-copy overhead #11151.
- Adopted
If-Modified-Sincefor conditional metadata fetches, avoiding re-downloading unchanged registry metadata #11161. - Switched to abbreviated metadata when checking
minimumReleaseAge, reducing the amount of data fetched from the registry #11160. - Switched the metadata cache to NDJSON format, improving read/write performance #11188.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-dev.100514 Nov 2025pre-release
Nothing published for this version
- 11.0.0-dev.100314 Nov 2025pre-release
Nothing published for this version
- 11.0.0-dev.100213 Nov 2025pre-release
Nothing published for this version
- 11.0.0-dev.100113 Nov 2025pre-release
Nothing published for this version
- 11.0.0-beta.4-129 Mar 2026pre-release
Nothing published for this version
- 11.0.0-beta.4-029 Mar 2026pre-release
Nothing published for this version
- 11.0.0-beta.88 Apr 2026pre-release
Release notes
Open source →Major Changes
CLI Output
- Use cleaner output for script execution. Print
$ commandinstead of> pkg@version stage path\n> command. Show project name and path only when running in a different directory. The$ commandline is printed to stderr to keep stdout clean for piping #11132. - During install, instead of rendering the full peer dependency issues tree, suggest running
pnpm peers checkto view the issues #11133.
Lifecycle Scripts
- pnpm no longer populates
npm_config_*environment variables from the pnpm config during lifecycle scripts. Only well-knownnpm_*env vars are now set, matching Yarn's behavior #11116.
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrue,verifyDepsBeforeRunis nowinstall, andminimumReleaseAgeis now1440(1 day). Newly published packages will not be resolved until they are at least 1 day old. This protects against supply chain attacks by giving the community time to detect and remove compromised versions. To opt out, setminimumReleaseAge: 0inpnpm-workspace.yaml#11158. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer reads all settings from
.npmrc. Only auth and registry settings are read from.npmrcfiles. All other settings (likehoistPattern,nodeLinker,shamefullyHoist, etc.) must be configured inpnpm-workspace.yamlor the global~/.config/pnpm/config.yaml#11189. -
Network settings (
httpProxy,httpsProxy,noProxy,localAddress,strictSsl,gitShallowHosts) are now written toconfig.yaml(global) orpnpm-workspace.yaml(local) instead of.npmrc/auth.ini. They are still readable from.npmrcfor easier migration from the npm CLI #11209.pnpm no longer reads
npm_config_*environment variables. Usepnpm_config_*environment variables instead (e.g.,pnpm_config_registryinstead ofnpm_config_registry).pnpm no longer reads the npm global config at
$PREFIX/etc/npmrc.pnpm loginwrites auth tokens to~/.config/pnpm/auth.ini.New
registriessetting inpnpm-workspace.yaml:registries: default: https://registry.npmjs.org/ "@my-org": https://private.example.com/ "@internal": https://nexus.corp.com/Auth tokens in
~/.npmrcstill work — pnpm continues to read~/.npmrcas a fallback for registry authentication. The newnpmrcAuthFilesetting can be used to point to a different file instead of~/.npmrc. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies,ignoredBuiltDependencies, andignoreDepScripts#11220.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added native
pnpm view(info,show,v) command for viewing package metadata from the registry #11064. - Added
pnpm login(andpnpm adduseralias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #11094. - Added
pnpm logoutcommand for logging out of npm registries. Revokes the authentication token on the registry and removes it from the local auth config file #11213. - Added native
pnpm deprecateandpnpm undeprecatecommands for setting and removing deprecation messages on package versions without delegating to the npm CLI #11120. - Added native
pnpm unpublishcommand. Supports unpublishing specific versions, version ranges via semver, and entire packages with--force#11128. - Added native
pnpm dist-tagcommand (ls,add,rmsubcommands) #11218. - Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964. -
Added
nodeDownloadMirrorssetting to configure custom Node.js download mirrors inpnpm-workspace.yaml. This replaces thenode-mirror:<channel>.npmrcsetting, which is no longer read #11194:nodeDownloadMirrors: release: https://my-mirror.example.com/download/release/
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- The built-in
clean,setup,deploy, andrebuildcommands now prefer user scripts over built-in commands. When a project'spackage.jsonhas a script with the same name,pnpmexecutes the script instead of the built-in command. Addedpurgeas an alias for the built-incleancommand, which always runs the built-in regardless of scripts #11118. - Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.pnpm audit --fixnow adds the minimum patched version for each advisory tominimumReleaseAgeExcludeinpnpm-workspace.yaml, so the security fix can be installed without waiting forminimumReleaseAge#11216.- Warn when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Replaced
node-fetchwith nativeundicifor HTTP requests throughout pnpm #10537. - Skip redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Skip the staging directory when importing packages into
node_modules. This avoids the overhead of creating a temp dir and renaming per package #11088. - Write CAS files directly to their final content-addressed path instead of writing to a temp file and renaming. Eliminates ~30k rename syscalls per cold install #11087.
- Optimize hot path string operations in content-addressable store and increase
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086. - Improved HTTP performance with Happy Eyeballs (dual-stack), better keep-alive settings, and an optimized global dispatcher. Tarball downloads with known size now pre-allocate memory to avoid double-copy overhead #11151.
- Use
If-Modified-Sincefor conditional metadata fetches, avoiding re-downloading unchanged registry metadata #11161. - Use abbreviated metadata when checking
minimumReleaseAge, reducing the amount of data fetched from the registry #11160. - Use NDJSON format for the metadata cache, improving read/write performance #11188.
Patch Changes
-
Use
process.stderr.writeinstead ofconsole.errorfor script logging #11140. -
Respect
frozen-lockfileflag when migrating config dependencies #11067. -
Removed
--workspaceflag from theversioncommand #11115. -
Handle
ENOTSUPerror in clone import path during parallel I/O #11117. -
Fixed
pnpm auditcommand. -
Updated dependencies to fix vulnerabilities.
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043. -
Fixed a crash in the lockfile merger when merging non-semver version strings (e.g.
link:,file:, git URLs) #11102. -
Handle
ENOTSUPerror inlinkOrCopyduring parallel imports #11103. -
Skip linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #11069.
-
Fix
_passwordhandling for the default registry to decode from base64 before use, consistent with scoped registry behavior #11089. -
Fix a bug where the CAS locker cache was not updated when a file already existed with correct integrity #11085.
-
Prevent catalog entries from being removed by
cleanupUnusedCatalogswhen they are referenced only from workspaceoverrides#11075. -
Resolve patch file paths during
pnpm fetch#11054. -
Fixed invalid specifiers for peers on all non-exact version selectors #11049.
-
Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #11000.
-
Prepended
Bearerto the authorization token generated bytokenHelperif it is missing, aligning with npm's behavior #11097. -
Propagate error cause when throwing
PnpmErrorin@pnpm/npm-resolver#10990. -
Fix SQLite race condition during store initialization on Windows.
-
Remove
rimrafSyncinimportIndexedDirfast-path error handler #11168. -
Fixed
pnpm dedupe --checkunexpectedly failing due to non-deterministic resolution #11110. -
Fixed empty files not being rejected in
isEmptyDirOrNothing#11182. -
Fixed
.bat/.cmdtoken helpers not working on Windows due to missingshell: trueoption.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Use cleaner output for script execution. Print
- 11.0.0-beta.75 Apr 2026pre-release
Release notes
Open source →Major Changes
CLI Output
- Use cleaner output for script execution. Print
$ commandinstead of> pkg@version stage path\n> command. Show project name and path only when running in a different directory. The$ commandline is printed to stderr to keep stdout clean for piping #11132. - During install, instead of rendering the full peer dependency issues tree, suggest running
pnpm peers checkto view the issues #11133.
Lifecycle Scripts
- pnpm no longer populates
npm_config_*environment variables from the pnpm config during lifecycle scripts. Only well-knownnpm_*env vars are now set, matching Yarn's behavior #11116.
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrue,verifyDepsBeforeRunis nowinstall, andminimumReleaseAgeis now1440(1 day). Newly published packages will not be resolved until they are at least 1 day old. This protects against supply chain attacks by giving the community time to detect and remove compromised versions. To opt out, setminimumReleaseAge: 0inpnpm-workspace.yaml#11158. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer reads all settings from
.npmrc. Only auth and registry settings are read from.npmrcfiles. All other settings (likehoistPattern,nodeLinker,shamefullyHoist, etc.) must be configured inpnpm-workspace.yamlor the global~/.config/pnpm/config.yaml#11189.pnpm no longer reads
npm_config_*environment variables. Usepnpm_config_*environment variables instead (e.g.,pnpm_config_registryinstead ofnpm_config_registry).pnpm no longer reads the npm global config at
$PREFIX/etc/npmrc.pnpm loginwrites auth tokens to~/.config/pnpm/auth.ini.New
registriessetting inpnpm-workspace.yaml:registries: default: https://registry.npmjs.org/ "@my-org": https://private.example.com/ "@internal": https://nexus.corp.com/Auth tokens in
~/.npmrcstill work — pnpm continues to read~/.npmrcas a fallback for registry authentication. The newnpmrcAuthFilesetting can be used to point to a different file instead of~/.npmrc. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added native
pnpm view(info,show,v) command for viewing package metadata from the registry #11064. - Added
pnpm login(andpnpm adduseralias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #11094. - Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964. -
Added
nodeDownloadMirrorssetting to configure custom Node.js download mirrors inpnpm-workspace.yaml. This replaces thenode-mirror:<channel>.npmrcsetting, which is no longer read #11194:nodeDownloadMirrors: release: https://my-mirror.example.com/download/release/
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- The built-in
clean,setup,deploy, andrebuildcommands now prefer user scripts over built-in commands. When a project'spackage.jsonhas a script with the same name,pnpmexecutes the script instead of the built-in command. Addedpurgeas an alias for the built-incleancommand, which always runs the built-in regardless of scripts #11118. - Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.- Warn when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Replaced
node-fetchwith nativeundicifor HTTP requests throughout pnpm #10537. - Skip redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Skip the staging directory when importing packages into
node_modules. This avoids the overhead of creating a temp dir and renaming per package #11088. - Write CAS files directly to their final content-addressed path instead of writing to a temp file and renaming. Eliminates ~30k rename syscalls per cold install #11087.
- Optimize hot path string operations in content-addressable store and increase
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086. - Improved HTTP performance with Happy Eyeballs (dual-stack), better keep-alive settings, and an optimized global dispatcher. Tarball downloads with known size now pre-allocate memory to avoid double-copy overhead #11151.
- Use
If-Modified-Sincefor conditional metadata fetches, avoiding re-downloading unchanged registry metadata #11161. - Use abbreviated metadata when checking
minimumReleaseAge, reducing the amount of data fetched from the registry #11160. - Use NDJSON format for the metadata cache, improving read/write performance #11188.
Patch Changes
-
Use
process.stderr.writeinstead ofconsole.errorfor script logging #11140. -
Respect
frozen-lockfileflag when migrating config dependencies #11067. -
Removed
--workspaceflag from theversioncommand #11115. -
Handle
ENOTSUPerror in clone import path during parallel I/O #11117. -
Fixed
pnpm auditcommand. -
Updated dependencies to fix vulnerabilities.
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043. -
Fixed a crash in the lockfile merger when merging non-semver version strings (e.g.
link:,file:, git URLs) #11102. -
Handle
ENOTSUPerror inlinkOrCopyduring parallel imports #11103. -
Skip linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #11069.
-
Fix
_passwordhandling for the default registry to decode from base64 before use, consistent with scoped registry behavior #11089. -
Fix a bug where the CAS locker cache was not updated when a file already existed with correct integrity #11085.
-
Prevent catalog entries from being removed by
cleanupUnusedCatalogswhen they are referenced only from workspaceoverrides#11075. -
Resolve patch file paths during
pnpm fetch#11054. -
Fixed invalid specifiers for peers on all non-exact version selectors #11049.
-
Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #11000.
-
Prepended
Bearerto the authorization token generated bytokenHelperif it is missing, aligning with npm's behavior #11097. -
Propagate error cause when throwing
PnpmErrorin@pnpm/npm-resolver#10990. -
Fix SQLite race condition during store initialization on Windows.
-
Remove
rimrafSyncinimportIndexedDirfast-path error handler #11168.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Use cleaner output for script execution. Print
- 11.0.0-beta.630 Mar 2026pre-release
Release notes
Open source →Major Changes
CLI Output
- Use cleaner output for script execution. Print
$ commandinstead of> pkg@version stage path\n> command. Show project name and path only when running in a different directory. The$ commandline is printed to stderr to keep stdout clean for piping #11132. - During install, instead of rendering the full peer dependency issues tree, suggest running
pnpm peers checkto view the issues #11133.
Lifecycle Scripts
- pnpm no longer populates
npm_config_*environment variables from the pnpm config during lifecycle scripts. Only well-knownnpm_*env vars are now set, matching Yarn's behavior #11116.
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added native
pnpm view(info,show,v) command for viewing package metadata from the registry #11064. - Added
pnpm login(andpnpm adduseralias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #11094. - Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- The built-in
clean,setup,deploy, andrebuildcommands now prefer user scripts over built-in commands. When a project'spackage.jsonhas a script with the same name,pnpmexecutes the script instead of the built-in command. Addedpurgeas an alias for the built-incleancommand, which always runs the built-in regardless of scripts #11118. - Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.- Warn when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Replaced
node-fetchwith nativeundicifor HTTP requests throughout pnpm #10537. - Skip redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Skip the staging directory when importing packages into
node_modules. This avoids the overhead of creating a temp dir and renaming per package #11088. - Write CAS files directly to their final content-addressed path instead of writing to a temp file and renaming. Eliminates ~30k rename syscalls per cold install #11087.
- Optimize hot path string operations in content-addressable store and increase
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086.
Patch Changes
-
Use
process.stderr.writeinstead ofconsole.errorfor script logging #11140. -
Respect
frozen-lockfileflag when migrating config dependencies #11067. -
Removed
--workspaceflag from theversioncommand #11115. -
Handle
ENOTSUPerror in clone import path during parallel I/O #11117. -
Fixed
pnpm auditcommand. -
Updated dependencies to fix vulnerabilities.
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043. -
Fixed a crash in the lockfile merger when merging non-semver version strings (e.g.
link:,file:, git URLs) #11102. -
Handle
ENOTSUPerror inlinkOrCopyduring parallel imports #11103. -
Skip linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #11069.
-
Fix
_passwordhandling for the default registry to decode from base64 before use, consistent with scoped registry behavior #11089. -
Fix a bug where the CAS locker cache was not updated when a file already existed with correct integrity #11085.
-
Prevent catalog entries from being removed by
cleanupUnusedCatalogswhen they are referenced only from workspaceoverrides#11075. -
Resolve patch file paths during
pnpm fetch#11054. -
Fixed invalid specifiers for peers on all non-exact version selectors #11049.
-
Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #11000.
-
Prepended
Bearerto the authorization token generated bytokenHelperif it is missing, aligning with npm's behavior #11097. -
Propagate error cause when throwing
PnpmErrorin@pnpm/npm-resolver#10990.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Use cleaner output for script execution. Print
- 11.0.0-beta.529 Mar 2026pre-release
Release notes
Open source →Major Changes
CLI Output
- Use cleaner output for script execution. Print
$ commandinstead of> pkg@version stage path\n> command. Show project name and path only when running in a different directory. The$ commandline is printed to stderr to keep stdout clean for piping #11132. - During install, instead of rendering the full peer dependency issues tree, suggest running
pnpm peers checkto view the issues #11133.
Lifecycle Scripts
- pnpm no longer populates
npm_config_*environment variables from the pnpm config during lifecycle scripts. Only well-knownnpm_*env vars are now set, matching Yarn's behavior #11116.
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added native
pnpm view(info,show,v) command for viewing package metadata from the registry #11064. - Added
pnpm login(andpnpm adduseralias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #11094. - Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- The built-in
clean,setup,deploy, andrebuildcommands now prefer user scripts over built-in commands. When a project'spackage.jsonhas a script with the same name,pnpmexecutes the script instead of the built-in command. Addedpurgeas an alias for the built-incleancommand, which always runs the built-in regardless of scripts #11118. - Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.- Warn when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Replaced
node-fetchwith nativeundicifor HTTP requests throughout pnpm #10537. - Skip redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Skip the staging directory when importing packages into
node_modules. This avoids the overhead of creating a temp dir and renaming per package #11088. - Write CAS files directly to their final content-addressed path instead of writing to a temp file and renaming. Eliminates ~30k rename syscalls per cold install #11087.
- Optimize hot path string operations in content-addressable store and increase
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086.
Patch Changes
-
Use
process.stderr.writeinstead ofconsole.errorfor script logging #11140. -
Respect
frozen-lockfileflag when migrating config dependencies #11067. -
Removed
--workspaceflag from theversioncommand #11115. -
Handle
ENOTSUPerror in clone import path during parallel I/O #11117. -
Fixed
pnpm auditcommand. -
Updated dependencies to fix vulnerabilities.
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043. -
Fixed a crash in the lockfile merger when merging non-semver version strings (e.g.
link:,file:, git URLs) #11102. -
Handle
ENOTSUPerror inlinkOrCopyduring parallel imports #11103. -
Skip linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #11069.
-
Fix
_passwordhandling for the default registry to decode from base64 before use, consistent with scoped registry behavior #11089. -
Fix a bug where the CAS locker cache was not updated when a file already existed with correct integrity #11085.
-
Prevent catalog entries from being removed by
cleanupUnusedCatalogswhen they are referenced only from workspaceoverrides#11075. -
Resolve patch file paths during
pnpm fetch#11054. -
Fixed invalid specifiers for peers on all non-exact version selectors #11049.
-
Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #11000.
-
Prepended
Bearerto the authorization token generated bytokenHelperif it is missing, aligning with npm's behavior #11097. -
Propagate error cause when throwing
PnpmErrorin@pnpm/npm-resolver#10990.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- Use cleaner output for script execution. Print
- 11.0.0-beta.429 Mar 2026pre-release
Nothing published for this version
- 11.0.0-beta.326 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003. - Added
pnpm peers checkcommand that checks for unmet and missing peer dependency issues by reading the lockfile #7087. - Implemented the
versioncommand natively in pnpm to support workspaces andworkspace:protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #10879.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Added a new
dedupePeerssetting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like([email protected]([email protected])). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #11070. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030. - Added
pnandpnxshort aliases forpnpmandpnpx(pnpm dlx) #11052. pnpm store prunenow displays the total size of removed files #11047.- Warn when
optimisticRepeatInstallskipsshouldRefreshResolutionhooks #10995.
Performance
- Skip redundant internal linking during GVS warm reinstall when no packages were added #11073.
- Skip the staging directory when importing packages into
node_modules. This avoids the overhead of creating a temp dir and renaming per package #11088. - Write CAS files directly to their final content-addressed path instead of writing to a temp file and renaming. Eliminates ~30k rename syscalls per cold install #11087.
- Optimize hot path string operations in content-addressable store and increase
gunzipSyncchunk size for fewer buffer allocations during tarball decompression #11086.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043. -
Fixed a crash in the lockfile merger when merging non-semver version strings (e.g.
link:,file:, git URLs) #11102. -
Handle
ENOTSUPerror inlinkOrCopyduring parallel imports #11103. -
Skip linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #11069.
-
Fix
_passwordhandling for the default registry to decode from base64 before use, consistent with scoped registry behavior #11089. -
Fix a bug where the CAS locker cache was not updated when a file already existed with correct integrity #11085.
-
Prevent catalog entries from being removed by
cleanupUnusedCatalogswhen they are referenced only from workspaceoverrides#11075. -
Resolve patch file paths during
pnpm fetch#11054. -
Fixed invalid specifiers for peers on all non-exact version selectors #11049.
-
Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #11000.
-
Prepended
Bearerto the authorization token generated bytokenHelperif it is missing, aligning with npm's behavior #11097. -
Propagate error cause when throwing
PnpmErrorin@pnpm/npm-resolver#10990.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-beta.221 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-beta.121 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
-
Stop falling back to the npm CLI. Commands that were previously passed through to npm (
access,adduser,bugs,deprecate,dist-tag,docs,edit,find,home,info,issues,login,logout,owner,ping,prefix,profile,pkg,repo,search,set-script,show,star,stars,team,token,unpublish,unstar,version,view,whoami,xmas) and their aliases (s,se,v) now throw a "not implemented" error with a suggestion to use the npm CLI directly #10642. -
Store globally installed binaries in a
binsubdirectory ofPNPM_HOMEinstead of directly inPNPM_HOME. This prevents internal directories likeglobal/andstore/from polluting shell autocompletion whenPNPM_HOMEis on PATH #10986. After upgrading, runpnpm setupto update your shell configuration.
Minor Changes
New Commands
- Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341. - Added
pnpm cicommand for clean installs #6100. The command runspnpm cleanfollowed bypnpm install --frozen-lockfile. Designed for CI/CD environments where reproducible builds are critical. Aliases:pnpm clean-install,pnpm ic,pnpm install-clean#11003.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- Added
-Fas a short alias for the--filteroption. - Added support for hidden scripts. Scripts starting with
.are hidden and cannot be run directly viapnpm run. They can only be called from other scripts. Hidden scripts are also omitted from thepnpm runlisting #11041. - Allow
pnpm approve-buildsto receive positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with!to deny it. Only mentioned packages are affected; the rest are left untouched #11030. - During install, packages with ignored builds that are not yet listed in
allowBuildsare automatically added topnpm-workspace.yamlwith a placeholder value, so users can manually set them totrueorfalse#11030.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
-
Fixed
strictDepBuildsandallowBuildschecks being bypassed when a package's build side-effects are cached in the store #11039. -
In GVS mode,
pnpm approve-buildsnow runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changingallowBuilds#11043.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-beta.019 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksIf the registry requests OTP and the user has not provided it via the
PNPM_CONFIG_OTPenvironment variable or the--otpflag, pnpm will prompt the user directly for an OTP code.If the registry requests web-based authentication, pnpm will print a scannable QR code along with the URL.
Since the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
pnpm no longer reads settings from the
pnpmfield ofpackage.json. Settings should be defined inpnpm-workspace.yaml#10086. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
Minor Changes
New Commands
- Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. - Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. - Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. - Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix=update#10341.
Configuration
-
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new setting
virtualStoreOnlythat populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts.pnpm fetchnow uses this mode internally #10840. -
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964.
Store
- When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Hooks & Pnpmfiles
- Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. - Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded.
CLI & Other
- Added
-Fas a short alias for the--filteroption.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
-
Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled #10978.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-alpha.1615 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
Minor Changes
-
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964. -
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved. -
Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. -
Allow loading certificates from
cert,ca, andkeyfor specific registry URLs. E.g.,//registry.example.com/:ca=-----BEGIN CERTIFICATE-----.... Previously this was only working viacertfile,cafile, andkeyfile#10230. -
Added
--allflag topnpm approve-buildsthat approves all pending builds without interactive prompts #10136. -
Added a new setting
blockExoticSubdepsthat prevents the resolution of exotic protocols in transitive dependencies #10265. -
Added
trustPolicyIgnoreAfter, which allows you to ignore trust policy checks for packages published more than a specified time ago #10352. -
Added a new flag called
--baretopnpm initfor creating a package.json with the bare minimum of required fields #10226. -
Added support for
allowBuilds, which is a new field that can be used instead ofonlyBuiltDependenciesandignoredBuiltDependencies#10311. -
Added support for object type in
configDependencieswhen the tarball URL returned from package metadata differs from the computed URL #10431. -
The
pnpm dlx/pnpxcommand now supports thecatalog:protocol. Example:pnpm dlx shx@catalog:. -
Add support for a hook called
beforePackingthat can be used to customize thepackage.jsoncontents at publish time #3816. -
On systems using the musl C library (e.g. Alpine Linux),
pnpm env usenow automatically downloads the musl variant of Node.js.pnpm env addandpnpm env removesubcommands have been removed.pnpm env listnow only lists remote Node.js versions. -
Added support for
--dry-runto thepackcommand #10301. -
Added mark-and-sweep garbage collection for global virtual store.
pnpm store prunenow removes unused packages from the global virtual store'slinks/directory. -
Semi-breaking. Changed the location of unscoped packages in the virtual global store. They will now be stored under a directory named
@to maintain a uniform 4-level directory depth. -
Support configuring
auditLevelin thepnpm-workspace.yamlfile #10540. -
Support bare
workspace:protocol without version specifier. It is now treated asworkspace:*and resolves to the concrete version during publish #10436. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. -
Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. -
Increase the network concurrency on machines with many CPU cores #10068.
-
Added support for
trustPolicyExclude#10164. -
Compute integrity hash for HTTP tarball dependencies when fetching, storing it in the lockfile to prevent servers from serving altered content on subsequent installs #10287.
-
Added support for automatic Node.js runtime installation for dependencies. pnpm will now install the Node.js version required by a dependency if that dependency declares a Node.js runtime in the
enginesfield #10141. -
Allow overriding the
enginesfield on publish by thepublishConfig.enginesfield. -
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
Added a new setting:
trustPolicy. When set tono-downgrade, pnpm will fail installation if a package's trust level has decreased compared to previous releases #8889. -
Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded. -
Added
-Fas a short alias for the--filteroption. -
When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
-
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix --fix-mode=update#10341.
Patch Changes
-
Fixed global install output showing
???instead of the linked package path when linking from the current directory #10899. -
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-alpha.1515 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
Minor Changes
-
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in
pnpm-lock.yamlinstead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912 #10964. -
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved. -
Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. -
Allow loading certificates from
cert,ca, andkeyfor specific registry URLs. E.g.,//registry.example.com/:ca=-----BEGIN CERTIFICATE-----.... Previously this was only working viacertfile,cafile, andkeyfile#10230. -
Added
--allflag topnpm approve-buildsthat approves all pending builds without interactive prompts #10136. -
Added a new setting
blockExoticSubdepsthat prevents the resolution of exotic protocols in transitive dependencies #10265. -
Added
trustPolicyIgnoreAfter, which allows you to ignore trust policy checks for packages published more than a specified time ago #10352. -
Added a new flag called
--baretopnpm initfor creating a package.json with the bare minimum of required fields #10226. -
Added support for
allowBuilds, which is a new field that can be used instead ofonlyBuiltDependenciesandignoredBuiltDependencies#10311. -
Added support for object type in
configDependencieswhen the tarball URL returned from package metadata differs from the computed URL #10431. -
The
pnpm dlx/pnpxcommand now supports thecatalog:protocol. Example:pnpm dlx shx@catalog:. -
Add support for a hook called
beforePackingthat can be used to customize thepackage.jsoncontents at publish time #3816. -
On systems using the musl C library (e.g. Alpine Linux),
pnpm env usenow automatically downloads the musl variant of Node.js.pnpm env addandpnpm env removesubcommands have been removed.pnpm env listnow only lists remote Node.js versions. -
Added support for
--dry-runto thepackcommand #10301. -
Added mark-and-sweep garbage collection for global virtual store.
pnpm store prunenow removes unused packages from the global virtual store'slinks/directory. -
Semi-breaking. Changed the location of unscoped packages in the virtual global store. They will now be stored under a directory named
@to maintain a uniform 4-level directory depth. -
Support configuring
auditLevelin thepnpm-workspace.yamlfile #10540. -
Support bare
workspace:protocol without version specifier. It is now treated asworkspace:*and resolves to the concrete version during publish #10436. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. -
Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. -
Increase the network concurrency on machines with many CPU cores #10068.
-
Added support for
trustPolicyExclude#10164. -
Compute integrity hash for HTTP tarball dependencies when fetching, storing it in the lockfile to prevent servers from serving altered content on subsequent installs #10287.
-
Added support for automatic Node.js runtime installation for dependencies. pnpm will now install the Node.js version required by a dependency if that dependency declares a Node.js runtime in the
enginesfield #10141. -
Allow overriding the
enginesfield on publish by thepublishConfig.enginesfield. -
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
Added a new setting:
trustPolicy. When set tono-downgrade, pnpm will fail installation if a package's trust level has decreased compared to previous releases #8889. -
Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded. -
Added
-Fas a short alias for the--filteroption. -
When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
-
Support specifying the pnpm version via
devEngines.packageManagerinpackage.json. Unlike thepackageManagerfield, this supports version ranges. The resolved version is stored inpnpm-lock.yamland reused if it still satisfies the range #10932. -
Add the ability to fix vulnerabilities by updating packages in the lockfile instead of adding overrides. Use
pnpm audit --fix --fix-mode=update#10341.
Patch Changes
-
Fixed global install output showing
???instead of the linked package path when linking from the current directory #10899. -
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-alpha.1411 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Lockfile
- Simplified
patchedDependencieslockfile format fromRecord<string, { path: string, hash: string }>toRecord<string, string>(selector to hash). Existing lockfiles with the old format are automatically migrated #10911.
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
Minor Changes
-
Config dependencies are now installed into the global virtual store (
{storeDir}/links/) and symlinked intonode_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #10910. -
Store config dependency and package manager integrity info in a separate
pnpm-lock.env.yamllockfile instead of inlining it inpnpm-workspace.yaml. The workspace manifest now contains only clean version specifiers forconfigDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the new env lockfile. The env lockfile also storespackageManagerDependenciesresolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #10912. -
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved. -
Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. -
Allow loading certificates from
cert,ca, andkeyfor specific registry URLs. E.g.,//registry.example.com/:ca=-----BEGIN CERTIFICATE-----.... Previously this was only working viacertfile,cafile, andkeyfile#10230. -
Added
--allflag topnpm approve-buildsthat approves all pending builds without interactive prompts #10136. -
Added a new setting
blockExoticSubdepsthat prevents the resolution of exotic protocols in transitive dependencies #10265. -
Added
trustPolicyIgnoreAfter, which allows you to ignore trust policy checks for packages published more than a specified time ago #10352. -
Added a new flag called
--baretopnpm initfor creating a package.json with the bare minimum of required fields #10226. -
Added support for
allowBuilds, which is a new field that can be used instead ofonlyBuiltDependenciesandignoredBuiltDependencies#10311. -
Added support for object type in
configDependencieswhen the tarball URL returned from package metadata differs from the computed URL #10431. -
The
pnpm dlx/pnpxcommand now supports thecatalog:protocol. Example:pnpm dlx shx@catalog:. -
Add support for a hook called
beforePackingthat can be used to customize thepackage.jsoncontents at publish time #3816. -
On systems using the musl C library (e.g. Alpine Linux),
pnpm env usenow automatically downloads the musl variant of Node.js.pnpm env addandpnpm env removesubcommands have been removed.pnpm env listnow only lists remote Node.js versions. -
Added support for
--dry-runto thepackcommand #10301. -
Added mark-and-sweep garbage collection for global virtual store.
pnpm store prunenow removes unused packages from the global virtual store'slinks/directory. -
Semi-breaking. Changed the location of unscoped packages in the virtual global store. They will now be stored under a directory named
@to maintain a uniform 4-level directory depth. -
Support configuring
auditLevelin thepnpm-workspace.yamlfile #10540. -
Support bare
workspace:protocol without version specifier. It is now treated asworkspace:*and resolves to the concrete version during publish #10436. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. -
Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. -
Increase the network concurrency on machines with many CPU cores #10068.
-
Added support for
trustPolicyExclude#10164. -
Compute integrity hash for HTTP tarball dependencies when fetching, storing it in the lockfile to prevent servers from serving altered content on subsequent installs #10287.
-
Added support for automatic Node.js runtime installation for dependencies. pnpm will now install the Node.js version required by a dependency if that dependency declares a Node.js runtime in the
enginesfield #10141. -
Allow overriding the
enginesfield on publish by thepublishConfig.enginesfield. -
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
Added a new setting:
trustPolicy. When set tono-downgrade, pnpm will fail installation if a package's trust level has decreased compared to previous releases #8889. -
Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded. -
Added
-Fas a short alias for the--filteroption. -
When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Patch Changes
-
Fixed global install output showing
???instead of the linked package path when linking from the current directory #10899. -
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-alpha.137 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
- Runtime dependencies are always linked from the global virtual store #10233.
- Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. - Store version bumped to v11.
- Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473. - Use SQLite for storing package index in the content-addressable store. Instead of individual JSON files under
$STORE/index/, package metadata is now stored in a single SQLite database at$STORE/index.dbwith MessagePack-encoded values. This reduces filesystem syscall overhead, improves space efficiency for small metadata entries, and enables concurrent access via SQLite's WAL mode. Packages missing from the new index are re-fetched on demand #10500 #10826.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
Minor Changes
-
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved. -
Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. -
Allow loading certificates from
cert,ca, andkeyfor specific registry URLs. E.g.,//registry.example.com/:ca=-----BEGIN CERTIFICATE-----.... Previously this was only working viacertfile,cafile, andkeyfile#10230. -
Added
--allflag topnpm approve-buildsthat approves all pending builds without interactive prompts #10136. -
Added a new setting
blockExoticSubdepsthat prevents the resolution of exotic protocols in transitive dependencies #10265. -
Added
trustPolicyIgnoreAfter, which allows you to ignore trust policy checks for packages published more than a specified time ago #10352. -
Added a new flag called
--baretopnpm initfor creating a package.json with the bare minimum of required fields #10226. -
Added support for
allowBuilds, which is a new field that can be used instead ofonlyBuiltDependenciesandignoredBuiltDependencies#10311. -
Added support for object type in
configDependencieswhen the tarball URL returned from package metadata differs from the computed URL #10431. -
The
pnpm dlx/pnpxcommand now supports thecatalog:protocol. Example:pnpm dlx shx@catalog:. -
Add support for a hook called
beforePackingthat can be used to customize thepackage.jsoncontents at publish time #3816. -
On systems using the musl C library (e.g. Alpine Linux),
pnpm env usenow automatically downloads the musl variant of Node.js.pnpm env addandpnpm env removesubcommands have been removed.pnpm env listnow only lists remote Node.js versions. -
Added support for
--dry-runto thepackcommand #10301. -
Added mark-and-sweep garbage collection for global virtual store.
pnpm store prunenow removes unused packages from the global virtual store'slinks/directory. -
Semi-breaking. Changed the location of unscoped packages in the virtual global store. They will now be stored under a directory named
@to maintain a uniform 4-level directory depth. -
Support configuring
auditLevelin thepnpm-workspace.yamlfile #10540. -
Support bare
workspace:protocol without version specifier. It is now treated asworkspace:*and resolves to the concrete version during publish #10436. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. -
Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. -
Increase the network concurrency on machines with many CPU cores #10068.
-
Added support for
trustPolicyExclude#10164. -
Compute integrity hash for HTTP tarball dependencies when fetching, storing it in the lockfile to prevent servers from serving altered content on subsequent installs #10287.
-
Added support for automatic Node.js runtime installation for dependencies. pnpm will now install the Node.js version required by a dependency if that dependency declares a Node.js runtime in the
enginesfield #10141. -
Allow overriding the
enginesfield on publish by thepublishConfig.enginesfield. -
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
Added a new setting:
trustPolicy. When set tono-downgrade, pnpm will fail installation if a package's trust level has decreased compared to previous releases #8889. -
Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded. -
Added
-Fas a short alias for the--filteroption. -
When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #10837.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
<!-- sponsors -->
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
<!-- sponsors end -->
- 11.0.0-alpha.121 Mar 2026pre-release
Release notes
Open source →Major Changes
Store
-
Runtime dependencies are always linked from the global virtual store #10233.
-
Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. -
Store version bumped to v11.
-
Switched internal store and cache files from JSON to MessagePack format for improved performance.
This change migrates all internal index files and metadata cache files to use MessagePack serialization instead of JSON. MessagePack provides faster serialization/deserialization and more compact file sizes, resulting in improved installation performance.
Related PR: #10500
-
Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473.
Global Packages
-
Global installs (
pnpm add -g pkg) andpnpm dlxnow use the global virtual store by default. Packages are stored at{storeDir}/linksinstead of per-project.pnpmdirectories. This can be disabled by settingenableGlobalVirtualStore: false#10694. -
Isolated global packages. Each globally installed package (or group of packages installed together) now gets its own isolated installation directory with its own
package.json,node_modules/, and lockfile. This prevents global packages from interfering with each other through peer dependency conflicts, hoisting changes, or version resolution shifts.Key changes:
pnpm add -g <pkg>creates an isolated installation in{pnpmHomeDir}/global/v11/{hash}/pnpm remove -g <pkg>removes the entire installation group containing the packagepnpm update -g [pkg]re-installs packages in new isolated directoriespnpm list -gscans isolated directories to show all installed global packagespnpm install -g(no args) is no longer supported; usepnpm add -g <pkg>instead
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround. -
Breaking changes to
pnpm link:pnpm link <pkg-name>no longer resolves packages from the global store. Only relative or absolute paths are accepted. For example, usepnpm link ./fooinstead ofpnpm link foo.pnpm link --globalis removed. Usepnpm add -g .to register a local package's bins globally.pnpm link(no arguments) is removed. Usepnpm link <dir>with an explicit path instead.
-
Do not exclude the root workspace project, when it is explicitly selected via a filter #10465.
Minor Changes
-
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved. -
Added
pnpm sbomcommand for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #9088. -
Allow loading certificates from
cert,ca, andkeyfor specific registry URLs. E.g.,//registry.example.com/:ca=-----BEGIN CERTIFICATE-----.... Previously this was only working viacertfile,cafile, andkeyfile#10230. -
Added
--allflag topnpm approve-buildsthat approves all pending builds without interactive prompts #10136. -
Added a new setting
blockExoticSubdepsthat prevents the resolution of exotic protocols in transitive dependencies #10265. -
Added
trustPolicyIgnoreAfter, which allows you to ignore trust policy checks for packages published more than a specified time ago #10352. -
Added a new flag called
--baretopnpm initfor creating a package.json with the bare minimum of required fields #10226. -
Added support for
allowBuilds, which is a new field that can be used instead ofonlyBuiltDependenciesandignoredBuiltDependencies#10311. -
Added support for object type in
configDependencieswhen the tarball URL returned from package metadata differs from the computed URL #10431. -
The
pnpm dlx/pnpxcommand now supports thecatalog:protocol. Example:pnpm dlx shx@catalog:. -
Add support for a hook called
beforePackingthat can be used to customize thepackage.jsoncontents at publish time #3816. -
On systems using the musl C library (e.g. Alpine Linux),
pnpm env usenow automatically downloads the musl variant of Node.js.pnpm env addandpnpm env removesubcommands have been removed.pnpm env listnow only lists remote Node.js versions. -
Added support for
--dry-runto thepackcommand #10301. -
Added mark-and-sweep garbage collection for global virtual store.
pnpm store prunenow removes unused packages from the global virtual store'slinks/directory. -
Semi-breaking. Changed the location of unscoped packages in the virtual global store. They will now be stored under a directory named
@to maintain a uniform 4-level directory depth. -
Support configuring
auditLevelin thepnpm-workspace.yamlfile #10540. -
Support bare
workspace:protocol without version specifier. It is now treated asworkspace:*and resolves to the concrete version during publish #10436. -
Added support for
pnpm config get globalconfigto retrieve the global config file path #9977. -
Added a new command
pnpm runtime set <runtime name> <runtime version spec> [-g]for installing runtimes. Deprecatedpnpm env usein favor of the new command. -
Added
pnpm cleancommand that safely removesnode_modulesdirectories from all workspace projects #10707. Use--lockfileto also removepnpm-lock.yamlfiles. -
Increase the network concurrency on machines with many CPU cores #10068.
-
Added support for
trustPolicyExclude#10164. -
Compute integrity hash for HTTP tarball dependencies when fetching, storing it in the lockfile to prevent servers from serving altered content on subsequent installs #10287.
-
Added support for automatic Node.js runtime installation for dependencies. pnpm will now install the Node.js version required by a dependency if that dependency declares a Node.js runtime in the
enginesfield #10141. -
Allow overriding the
enginesfield on publish by thepublishConfig.enginesfield. -
Changed default values:
optimisticRepeatInstallis nowtrueandverifyDepsBeforeRunis nowinstall. -
Added a new setting:
trustPolicy. When set tono-downgrade, pnpm will fail installation if a package's trust level has decreased compared to previous releases #8889. -
Support
.pnpmfile.mjsas the default pnpmfile. When.pnpmfile.mjsexists, it takes priority over.pnpmfile.cjsand only one is loaded. -
Added
-Fas a short alias for the--filteroption.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
-
- 11.0.0-alpha.1124 Feb 2026pre-release
Release notes
Open source →Major Changes
Store
-
Runtime dependencies are always linked from the global virtual store #10233.
-
Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. -
Store version bumped to v11.
-
Switched internal store and cache files from JSON to MessagePack format for improved performance.
This change migrates all internal index files and metadata cache files to use MessagePack serialization instead of JSON. MessagePack provides faster serialization/deserialization and more compact file sizes, resulting in improved installation performance.
Related PR: #10500
-
Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473.
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround.
Minor Changes
-
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
-
- 11.0.0-alpha.1023 Feb 2026pre-release
Release notes
Open source →Major Changes
Store
-
Runtime dependencies are always linked from the global virtual store #10233.
-
Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. -
Store version bumped to v11.
-
Switched internal store and cache files from JSON to MessagePack format for improved performance.
This change migrates all internal index files and metadata cache files to use MessagePack serialization instead of JSON. MessagePack provides faster serialization/deserialization and more compact file sizes, resulting in improved installation performance.
Related PR: #10500
-
Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473.
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround.
Minor Changes
-
7fab2a2: Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
cb367b9: Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
075aa99: Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
e146e98: Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
7d5ada0:
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
5bf7768: A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
2b14c74: When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
-
- 11.0.0-alpha.923 Feb 2026pre-release
Nothing published for this version
- 11.0.0-alpha.823 Feb 2026pre-release
Nothing published for this version
- 11.0.0-alpha.722 Feb 2026pre-release
Nothing published for this version
- 11.0.0-alpha.622 Feb 2026pre-release
Nothing published for this version
- 11.0.0-alpha.517 Feb 2026pre-release
Release notes
Open source →Major Changes
Store
-
Runtime dependencies are always linked from the global virtual store #10233.
-
Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. -
Store version bumped to v11.
-
Switched internal store and cache files from JSON to MessagePack format for improved performance.
This change migrates all internal index files and metadata cache files to use MessagePack serialization instead of JSON. MessagePack provides faster serialization/deserialization and more compact file sizes, resulting in improved installation performance.
Related PR: #10500
-
Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473.
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround.
Minor Changes
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
-
- 11.0.0-alpha.417 Feb 2026pre-release
Release notes
Open source →Major Changes
Store
-
Runtime dependencies are always linked from the global virtual store #10233.
-
Optimized index file format to store the hash algorithm once per file instead of repeating it for every file entry. Each file entry now stores only the hex digest instead of the full integrity string (
<algo>-<digest>). Using hex format improves performance since file paths in the content-addressable store use hex representation, eliminating base64-to-hex conversion during path lookups. -
Store version bumped to v11.
-
Switched internal store and cache files from JSON to MessagePack format for improved performance.
This change migrates all internal index files and metadata cache files to use MessagePack serialization instead of JSON. MessagePack provides faster serialization/deserialization and more compact file sizes, resulting in improved installation performance.
Related PR: #10500
-
Store the bundled manifest (name, version, bin, engines, scripts, etc.) directly in the package index file, eliminating the need to read
package.jsonfrom the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs #10473.
Configuration
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config get <array>now prints a JSON array. -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true
Other
-
This package is now pure ESM.
-
Node.js v18, 19, 20, and 21 support discontinued.
-
The standalone exe version of pnpm requires at least glibc 2.27.
-
strictDepBuildsistrueby default. -
blockExoticSubdepsistrueby default. -
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false -
Removed the deprecated
allowNonAppliedPatchescompletely in favor ofallowUnusedPatches. RemoveignorePatchFailuresso all patch application failures should throw an error. -
Removed the
pnpm servercommand #10463. -
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Removed support for
hooks.fetchers. We now have a new API for custom fetchers and resolvers via thefetchersfield ofpnpmfile. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
pnpm publishnow works without thenpmCLI.The One-time Password feature now reads from
PNPM_CONFIG_OTPinstead ofNPM_CONFIG_OTP:export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checksSince the new
pnpm publishno longer callsnpm publish, some undocumented features may have been unknowingly dropped. If you rely on a feature that is now gone, please open an issue at https://github.com/pnpm/pnpm/issues. In the meantime, you can usepnpm pack && npm publish *.tgzas a workaround.
Minor Changes
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Support reading
allowBuildsfrompnpm-workspace.yamlin the global package directory for global installs. -
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
pnpm whynow shows a reverse dependency tree. The searched package appears at the root with its dependents as branches, walking back to workspace roots. This replaces the previous forward-tree output which was noisy and hard to read for deeply nested dependencies. -
A new
--yesflag can be passed to pnpm to automatically confirm prompts. This is useful when running pnpm in non-interactive script. -
When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved.
Patch Changes
-
Check if a package is installable for non npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.
-
Explicitly tell
npmthe path to the globalrcconfig file. -
Fix YAML formatting preservation in
pnpm-workspace.yamlwhen running commands likepnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.Closes #10425
-
The parameter set by the
--allow-buildflag is written toallowBuilds. -
Fix a bug in which specifying
filteronpnpm-workspace.yamlwould cause pnpm to not detect any projects. -
Defer patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/sanity.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/sanity_light.svg" /> <img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/serpapi_dark.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/serpapi_light.svg" /> <img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160" alt="SerpApi" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/nx.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg" /> <img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" /> </picture> </a> </td> </tr> </tbody> </table>
-
- 11.0.0-alpha.313 Jan 2026pre-release
Release notes
Open source →Major Changes
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
Replace workspace project specific
.npmrcwithpackageConfigsinpnpm-workspace.yaml.A workspace manifest with
packageConfigswould look something like this:# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~"Or this:
# File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: - match: ["project-1", "project-2"] modulesDir: "node_modules" saveExact: true -
strictDepBuildsistrueby default. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
blockExoticSubdepsistrueby default. -
This package is now pure ESM.
-
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
The pnpm CLI now gets installed with a specific version of Node.js, which it uses for its runtime. This makes pnpm more stable and it doesn't rely on your globally install Node.js anymore.
-
Node.js v18 and 19 support discontinued.
-
pnpm config get <array>now prints a JSON array. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
Runtime dependencies are always linked from the global virtual store #10233.
-
Removed support for the
useNodeVersionandexecutionEnv.nodeVersionfields.devEngines.runtimeandengines.runtimeshould be used instead #10373. -
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
-
Remove deprecated build dependency settings:
onlyBuiltDependencies,onlyBuiltDependenciesFile,neverBuiltDependencies, andignoredBuiltDependencies.Use the
allowBuildssetting instead. It is a map where keys are package name patterns and values are booleans:truemeans the package is allowed to run build scriptsfalsemeans the package is explicitly denied from running build scripts
Same as before, by default, none of the packages in the dependencies are allowed to run scripts. If a package has postinstall scripts and it isn't declared in
allowBuilds, an error is printed.Before:
onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuildAfter:
allowBuilds: electron: true core-js: false esbuild: false
Minor Changes
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730. -
When pnpm updates the
pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> </tbody> </table>
-
- 11.0.0-alpha.215 Dec 2025pre-release
Release notes
Open source →Major Changes
-
pnpm config get(without--json) no longer print INI formatted text. Instead, it would print JSON for both objects and arrays and raw string for strings, numbers, booleans, and nulls.pnpm config get --jsonwould still print all types of values as JSON like before. -
pnpm config listandpnpm config get(without argument) now hide auth-related settings. -
This package is now pure ESM.
-
pnpm no longer loads non-auth and non-registry settings from rc files. Other settings must be defined in
pnpm-workspace.yaml. -
The pnpm CLI now gets installed with a specific version of Node.js, which it uses for its runtime. This makes pnpm more stable and it doesn't rely on your globally install Node.js anymore.
-
Node.js v18 and 19 support discontinued.
-
pnpm config get <array>now prints a JSON array. -
The default value of the
typefield in thepackage.jsonfile of the project initialized bypnpm initcommand has been changed tomodule. -
pnpm config listandpnpm config get(without argument) now show top-level keys as camelCase. Exception: Keys that start with@or//would be preserved (their cases don't change). -
The standalone exe version of pnpm requires at least glibc 2.27.
-
pnpm config listnow prints a JSON object instead of INI formatted text. -
pnpm config getandpnpm config listno longer load non camelCase options from the workspace manifest (pnpm-workspace.yaml). -
JSON files in the store and cache are replaced with binary files generated with v8.serialize.
Reading and deserializing a binary file generated with v8.serialize appears to be about 23% faster than reading and parsing a JSON file. Other operations are similar in speed. Therefore, we have switched to V8 binary files for storing data in pnpm’s global store and cache. The disadvantage of this approach is that V8 files generated by newer versions of Node.js cannot be deserialized by older versions. In such cases, we ignore the cache.
Related PR: #9971.
-
Runtime dependencies are always linked from the global virtual store #10233.
-
Support lowercase options in
pnpm add:-d,-p,-o,-e#9197.When using
pnpm addcommand only:-pis now an alias for--save-prodinstead of--parseable-dis now an alias for--save-devinstead of--loglevel=info
Minor Changes
-
Load environment variables whose names start with
pnpm_config_into config. These environment variables override settings frompnpm-workspace.yamlbut not the CLI arguments. -
Add support for a global YAML config file named
config.yaml.Now configurations are divided into 2 categories:
- Registry and auth settings which can be stored in INI files such as global
rcand local.npmrc. - pnpm-specific settings which can only be loaded from YAML files such as global
config.yamland localpnpm-workspace.yaml.
- Registry and auth settings which can be stored in INI files such as global
-
Added support for pnpmfiles written in ESM. They should have the
.mjsextension:.pnpmfile.mjs#9730.
Patch Changes
- Explicitly tell
npmthe path to the globalrcconfig file.
Platinum Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://bit.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a> </td> </tr> </tbody> </table>
Gold Sponsors
<table> <tbody> <tr> <td align="center" valign="middle"> <a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/discord.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/discord_light.svg" /> <img src="https://pnpm.io/img/users/discord.svg" width="220" alt="Discord" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/coderabbit.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/coderabbit_light.svg" /> <img src="https://pnpm.io/img/users/coderabbit.svg" width="220" alt="CodeRabbit" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/workleap.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/workleap_light.svg" /> <img src="https://pnpm.io/img/users/workleap.svg" width="190" alt="Workleap" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/stackblitz.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/stackblitz_light.svg" /> <img src="https://pnpm.io/img/users/stackblitz.svg" width="190" alt="Stackblitz" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"> </a> </td> </tr> </tbody> </table>
-