chore(deps): update pnpm to v11 #150

Open
renovate wants to merge 1 commit from renovate/pnpm-11.x into main
Collaborator

This PR contains the following updates:

Package Change Age Confidence
pnpm (source) 9.15.911.21.0 age confidence
pnpm (source) 811 age confidence

Release Notes

pnpm/pnpm (pnpm)

v11.21.0: pnpm 11.21

Compare Source

Minor Changes
  • Added interactive group selection to pnpm update --global --interactive.

  • Running pnpm setup, pnpm self-update, or a command that modifies the global installation (such as pnpm add --global) through sudo now prints a warning. pnpm keeps global packages and configuration in the invoking user's home directory, so running these commands as root silently operates on the root user's home directory instead of yours. They will fail with ERR_PNPM_SUDO_NOT_SUPPORTED in pnpm v12. Read-only global commands (such as pnpm bin --global) are unaffected.

Patch Changes
  • Fixed pnpm failing to start under asynchronous Node.js module loaders when no .pnpmfile.mjs exists pnpm/pnpm#11701.

  • Fixed minimumReleaseAge fallback for custom dist-tags so the selected version does not exceed the registry’s original tag target.

  • Removing a dependency from package.json and reinstalling no longer re-resolves the dependency graph. The importer's entry is dropped from pnpm-lock.yaml, anything it made unreachable is pruned, and a catalog entry that loses its last referent is removed — all without registry access. Installs still fall back to a full resolution when a package that stays resolves a peer dependency through the removed one, since that would change the surviving package's entry rather than only prune.

  • Changing a catalog entry to a different exact version no longer re-resolves the dependency graph. The package is replaced in pnpm-lock.yaml directly, reusing the same check the pnpm.overrides fast path applies: every locked dependency of the package must still satisfy the new version's manifest. Installs fall back to a full resolution when anything other than the catalog reaches the package — an importer that depends on it directly, or another package that depends on it — since the graph would then need both versions.

  • Fixed a CI regression where github:owner/repo dependencies (and other shorthand Git specifiers) would fail to install with Permission denied (publickey) on CI runners that lack SSH keys. The Git resolver no longer records an SSH URL unless the user explicitly wrote one (e.g. git+ssh:// or git@host:...):

    • The repository visibility probe (an HTTP HEAD request) now retries transient failures such as 429 Too Many Requests, so host throttling of CI runners is no longer mistaken for a private repository.
    • For non-SSH specifiers, anonymous HTTPS git ls-remote access is now tried before SSH, so a public repository whose visibility probe fails still resolves to a portable HTTPS URL instead of an SSH URL that only works where SSH keys are configured.
    • When every probe fails, the resolver falls back to HTTPS for shorthand and HTTPS-style specifiers, and only guesses SSH when the user explicitly provided an SSH URL.
    • A repository that could not be confirmed public is no longer resolved to the host's anonymous archive URL (e.g. codeload.github.com, which would fail to download for a private repository); it stays a regular git resolution so installs can use ambient Git credentials such as credential helpers and tokens.

    Note that a private repository that is reachable both over authenticated HTTPS and over SSH now resolves to its HTTPS URL, where previous versions recorded the SSH URL.

    Fixes pnpm/pnpm#13276.

  • ng build and nuxt build now work under the global virtual store: pnpm's built-in compatibility extensions add the tslib dependency that @angular/build uses without declaring and the unplugin dependency that @nuxt/vite-builder v4 uses without declaring.

  • Fixed link: dependencies under enableGlobalVirtualStore so linked children are materialized and slots remain isolated by their resolved link targets.

  • An install that skips resolution because pnpm-lock.yaml is already up to date now reacts fully to packages the lockfile removed — for example after pulling a lockfile in which a dependency was deleted. The hoist layer is recomputed, so a package that became hoistable when a direct dependency was removed is hoisted, and pendingBuilds entries for removed packages are dropped instead of staying pending forever.

  • The held-back-update warning printed by pnpm update no longer fires when minimumReleaseAge is the actual reason a newer version was not picked. The warning's baseline now applies the same maturity cutoff as the pick itself, so it no longer wrongly attributes the hold-back to "your manifests and already installed dependencies" or recommends an override that would defeat the age gate. See #​13071.

  • Checking whether ignoredOptionalDependencies is up to date no longer reorders the configured patterns. The check sorted them in place, which could move an ! exclusion ahead of the pattern it excludes from and flip which optional dependencies were ignored.

  • Changing autoInstallPeers, dedupePeers, peersSuffixMaxLength, excludeLinksFromLockfile, or injectWorkspacePackages no longer re-resolves the dependency graph when the lockfile proves the setting cannot affect it: no package or project declares a peer dependency for the peer settings, and no project depends on a directory or on another workspace project for the link and injection settings. The new setting is recorded in pnpm-lock.yaml and the install proceeds from the existing resolution. Every other case still falls back to a full resolution.

  • Adding, editing, or removing an entry in patchedDependencies no longer re-resolves the dependency graph. Resolution never reads a patch — it only records the patch file's hash against the package it matches — so the install now rewrites the affected entries in pnpm-lock.yaml and materializes the patched package from the store instead. Installs still fall back to a full resolution when the patched package is reachable as a peer dependency, and when the new configuration would leave a patch unused while allowUnusedPatches is off, so ERR_PNPM_UNUSED_PATCH is still reported.

  • Resolving a private git repository no longer blocks on an interactive credential prompt: git ls-remote now fails fast with an authentication error when git has no credentials for the repository #​13522.

  • Lockfile verification now honors offline mode by using cached registry metadata instead of reaching the registry. When the required metadata is not available locally, verification reports the same ERR_PNPM_NO_OFFLINE_META condition used by offline resolution.

  • POSIX shell shims now follow symbolic links before computing basedir, preventing execution failures when a shim is invoked via an external symlink on PATH #​13405.

  • The automatic packageManager version switch works again on registries whose tarball URLs point at a different host than the registry itself (load-balanced feed proxies, Artifactory-style mirrors). Package-manager entries are now always recorded with integrity-only resolutions — the download URL is derived from the trusted bootstrap registry instead — and entries persisted in an invalid shape by an earlier pnpm are discarded and re-resolved instead of failing every command #​13619.

  • Registries that serve no npm signature metadata (private mirrors and feed proxies commonly strip dist.signatures) no longer break the automatic packageManager version switch and pnpm self-update #​13147. When the configured registry cannot provide a verifiable signature, pnpm now fetches the signature from registry.npmjs.org and verifies it against the same embedded npm keys over the installed integrity — which proves exactly the same thing. If no signature can be obtained from either source (for example, both are unreachable, or the registry publishes only a shasum), pnpm proceeds with a warning instead of failing, but only when the packages resolve through a registry configured in the user's own (non-project) configuration; the download stays pinned by the lockfile integrity, and a signature that exists but does not validate still fails the switch.

  • pnpm fetch, and any install run with virtualStoreOnly, no longer writes a .pnp.cjs loader under nodeLinker: pnp. These installs populate the virtual store without linking the project, so the loader would have claimed the project resolves out of a store it was never linked into. The importer links and node_modules/.package-map.json were already skipped; the PnP loader now follows the same rule.

  • Prevent pnpm from removing project files when modulesDir resolves to the project root.

  • Speed up installs after adding ignoredOptionalDependencies patterns by removing newly ignored optional dependencies and pruning packages that are no longer reachable without resolving the dependency graph again.

  • When a failed install re-copies a bin script from the store, rerunning pnpm install now reapplies the executable bit to the bin instead of leaving it non-executable #​12742.

  • pnpm root -g and pnpm bin -g now print warnings to stderr instead of stdout, so their stdout stays a clean, machine-readable path. Previously, running either command with --global in a project that pins a package manager (e.g. via the packageManager field) printed a warning like [WARN] Using --global skips the package manager check for this project ahead of the path, breaking programs that capture the output as a path #​13672.

    In pnpm 12, pnpm root -g and pnpm prefix -g are now supported (they previously failed with ERR_PNPM_CLI_ROOT_GLOBAL_UNSUPPORTED / ERR_PNPM_CLI_PREFIX_GLOBAL_UNSUPPORTED), and the reporter output of dlx, create, config, sbom, with, store, prefix, root, and bin goes to stderr, matching pnpm 11.

  • pnpm setup no longer makes Node.js print a MODULE_TYPELESS_PACKAGE_JSON warning about dist/worker.js on every command. The package.json it writes next to a standalone executable now declares "type": "module".

  • pnpm update without saving no longer records a version that the manifest's range excludes. The kept range stays authoritative: a requested version outside it is skipped with a warning, and a requested range, a dist tag, or --latest resolves within it instead of past it. Previously each of these could write a lockfile entry that contradicted its own specifier, which the next pnpm install --frozen-lockfile rejected with ERR_PNPM_OUTDATED_LOCKFILE #​12764.

  • pnpm version -r --json now outputs [] instead of human-readable text when no pending changes exist pnpm/pnpm#13217.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.20.0: pnpm 11.20

Compare Source

Minor Changes
  • Security fix. Affects projects using namedRegistries on pnpm 11.1.0–11.19.x. It is semi-breaking for those projects — see "If you use named registries" below.

    The lockfile recorded no marker for which registry a package came from. Packages were keyed by name@version alone, and entry lookup went through refToRelative(ref, name), so a dependency you declared against one registry could be satisfied by an entry that was actually resolved from another. When two registries served the same name and version, both collapsed onto a single packages: entry and whichever resolved first decided the tarball every consumer got.

    That is a package-substitution risk: a package you expect from your private registry could be installed from a different registry that publishes the same name and version, and the lockfile recorded nothing that would let you tell.

    Packages resolved from a named registry are now recorded under registry-qualified keys (<name>@<registryName>:<version>, e.g. foo@work:1.0.0), so each registry gets its own entry and the lockfile pins which one a dependency came from.

    The lockfile format version is unchanged. Registry-qualified keys appear only for packages resolved from a named registry, so a project that does not use namedRegistries sees no difference, and older pnpm versions keep reading the file.

If you use named registries

Your next non-frozen install re-keys those entries, which shows up as a lockfile diff. Commit it — that diff is the fix being applied. Review it: an entry that moves to a registry you did not expect is worth investigating.

Everyone working on the project should be on this version or newer before you do. An older pnpm reads the re-keyed lockfile fine — frozen installs are unaffected — but it does not produce registry-qualified keys itself, so any install that updates the lockfile writes those entries back to the old shape, and the next install on a current pnpm re-qualifies them. The result is a lockfile that flips back and forth, and while it is in the old shape the project is exposed again. Because the lockfile format version is deliberately unchanged, pnpm cannot detect this and warn you about it.

There is no setting to keep the old behavior: the old shape is the vulnerability.

Tarball URLs that follow the standard registry layout are no longer written to the lockfile for named-registry packages; they are recomputed from the namedRegistries setting on demand.

To use named registries, map your aliases in pnpm-workspace.yaml:

namedRegistries:
  work: https://npm.enterprise.example.com/
New built-in npmjs: alias

npmjs: now resolves to https://registry.npmjs.org/ with no configuration, alongside the existing gh: alias for GitHub Packages. It pins a dependency to the public registry even when registry points elsewhere, such as an internal proxy:

{ "dependencies": { "left-pad": "npmjs:^1.3.0" } }

npm: cannot do this — it is the alias protocol (npm:<name>@<range>) and resolves through whatever registry points at.

If you mirror or proxy npmjs, point the alias at your mirror:

namedRegistries:
  npmjs: https://npm.internal.example.com/

Built-in registry URLs are also the prefixes a lockfile's recorded tarball URL is matched against when pnpm verifies a package. Without the override, an entry whose tarball URL is on registry.npmjs.org is verified against the public registry rather than your mirror. This only affects lockfiles that record such URLs — a canonical URL for your configured registry is omitted from the lockfile and unaffected — and only when a tarball-URL, minimumReleaseAge, or trustPolicy check runs. Overriding the alias is the same escape hatch GHES users already have for gh.

Every alias the lockfile references must stay in namedRegistries: reading an entry whose alias is gone fails with ERR_PNPM_MISSING_NAMED_REGISTRY rather than silently falling back to the default registry, since that would fetch a different package. Renaming an alias re-resolves the packages that used it.

Named registry aliases that shadow a reserved dependency specifier prefix (file, link, workspace, runtime, npm, jsr, ...) are now rejected with ERR_PNPM_RESERVED_NAMED_REGISTRY_NAME instead of being silently shadowed by the corresponding resolver.

pnpm licenses and pnpm sbom now keep the two artifacts apart as well: license records carry the registry alias, and SBOM components carry the purl repository_url qualifier.

Patch Changes
  • An empty http-proxy, https-proxy, proxy, or no-proxy value — from the .npmrc, pnpm-workspace.yaml, the CLI, or the HTTP_PROXY / HTTPS_PROXY / PROXY / NO_PROXY environment variables — no longer fails the install with ERR_PNPM_INVALID_PROXY. Empty settings read as unset, so a shell exporting HTTP_PROXY= disables the proxy, and an empty proxy= in the .npmrc no longer suppresses HTTPS_PROXY #​13533.

    proxy=false in the .npmrc or proxy: false in pnpm-workspace.yaml now turns proxying off instead of being read as a proxy host named false. false and null on https-proxy / http-proxy / no-proxy read as unset, and on the command line they are ordinary host names, since a flag carries its value verbatim.

  • The env lockfile no longer pins @pnpm/exe alongside pnpm when the wanted pnpm version is 12 or newer. From v12 the unscoped pnpm package is itself the native executable, so @pnpm/exe is not published for it and resolving it would fail. The engine identity check now verifies the native binary through whichever package ships it.

  • lexCompare and nerfDart are now published as @pnpm/text.ordinal-comparator and @pnpm/config.registry-auth-key. Use these instead of @pnpm/util.lex-comparator and @pnpm/config.nerf-dart.

  • Fixed the order in which pnpm matches a lockfile's recorded tarball URL against known registry URLs. Two registry URLs of equal length were previously ordered arbitrarily, so which one a tarball URL matched could differ between runs.

  • Dependency resolution is faster: package metadata is now filtered once per packument instead of once per dependency edge when minimumReleaseAge is active, and parsed semver versions and ranges are reused instead of re-parsed on every comparison.

  • Security: pnpm rebuild now refuses a lockfile whose packages key carries a path traversal in the package name (e.g. ../../../escaped@1.0.0), instead of running that package's lifecycle scripts and linking its bins in a directory outside the virtual store. Such a name is rejected with ERR_PNPM_INVALID_DEPENDENCY_NAME.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.19.0: pnpm 11.19

Compare Source

Minor Changes
  • pnpm login no longer requires an interactive terminal when the registry supports web-based login: without a TTY it prints the authentication URL (skipping the QR code and the "Press ENTER to open the URL in your browser" prompt) and polls the registry until the browser approval completes. Only the classic username/password login still fails with ERR_PNPM_LOGIN_NON_INTERACTIVE in a non-interactive terminal.

  • The save-prefix setting now accepts =: newly added dependencies are saved with an explicit = operator (=1.2.3) instead of the setting being silently treated as the default ^.

Patch Changes
  • allowBuilds entries can now approve git-hosted packages that pnpm downloads as a tarball, such as github: dependencies (which are fetched from codeload.github.com rather than cloned), by their repository URL without the resolved commit hash. This matches the hashless git+ matching already supported for cloned git dependencies. For example:

    allowBuilds:
      "foo@git+https://github.com/org/foo.git": true
    

    This approves the package whether pnpm clones it or downloads a tarball, so the entry no longer has to be updated every time the pinned commit changes. GitLab and Bitbucket tarball downloads are matched the same way. Approving or denying a specific resolved commit by its full tarball dep path continues to work.

  • pnpm outdated --include-github-actions no longer blocks on an interactive git credential prompt when a workflow uses a private action repo.

  • Prevented minimumReleaseAge from replacing latest with a SemVer-greater version than the registry tag target #​13034.

  • Fixed empty bundledDependencies and bundleDependencies arrays causing nondeterministic lockfile changes. See #​13123.

  • The install summary no longer prints (X is available) when the registry's dist-tags.latest is still held back by the active minimumReleaseAge policy. The hint only ever names the actual latest tag, so an immature latest suppresses the hint instead of advertising the version pnpm just refused to install #​11698.

  • pnpm update keeps the explicit = operator of an exact version pin: a dependency saved as =3.5.1 now updates to =3.5.2 instead of the bare 3.5.2. See #​13168.

  • Preserve a workspace dependency's link: entry when a run does not target it — e.g. pnpm update <other-pkg> (with or without --recursive), or a plain install after a root/catalog dependency change — with injectWorkspacePackages, instead of spuriously rewriting it to a peer-suffixed file: protocol. See #​10433.

  • Workspace dependencies declared with a relative path (e.g. "foo": "workspace:../foo") are no longer silently dropped from the workspace projects graph, so --filter selection and the topological order of recursive commands take them into account.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.18.0: pnpm 11.18

Compare Source

Minor Changes
  • Fixed an installed optional dependency being left without one of its own required dependencies. When a package reached through optionalDependencies is installable on the current system but one of its regular dependencies is not, a lockfile-based install skipped that dependency and installed the parent anyway, so importing the parent failed with MODULE_NOT_FOUND. The dependency is now installed, and an install-check warning reports the incompatibility. A dependency is still only skipped when every path to it is optional, or when the package that pulls it in was itself skipped #​13286.

  • pnpm setup now appends PNPM_HOME and the global bin directory to the GitHub Actions environment files (GITHUB_ENV and GITHUB_PATH), so later steps in the same job can run pnpm add --global and other global commands #​9191.

  • Added support for publishConfig.name, which publishes a package under a different name than the one its manifest carries in the workspace. It is for a project whose published name is already taken by a sibling project, which otherwise has to be renamed by a build step just before publishing. Only the published artifact is renamed — dependents, pnpm-lock.yaml, and release tooling keep addressing the project by its manifest name — and the new name reaches the packed manifest, the tarball filename, and everything that addresses the package at the registry: the already-published check of pnpm publish -r, its registry selection, and the release-planning probes of pnpm change status and pnpm version -r #​13345.

  • pnpm self-update no longer takes any instruction from the project it is run in:

    • pnpm is fetched through the same trusted registry and auth configuration used when switching pnpm versions, so a project .npmrc or pnpm-workspace.yaml can no longer redirect the download or attach credentials to it, and the project's default .pnpmfile.(c|m)js is no longer loaded. Pnpmfiles from trusted sources (the pnpmfile setting, the global pnpmfile, config dependencies) still apply.
    • The minimumReleaseAge settings in pnpm-workspace.yaml no longer affect self-update. They still govern the project's own dependencies; for self-update the cooldown now comes from the built-in default, your global config, a PNPM_CONFIG_* environment variable, or a command-line flag. This fixes self-update failing inside a workspace that raises the cutoff while succeeding everywhere else, and stops a repository from either waiving the cooldown or keeping you on an outdated pnpm by raising it.
    • The same applies to the trustPolicy settings and to ci: a project can no longer weaken the trust check that guards the pnpm download, nor re-enable the confirmation prompt that a CI run suppresses.

    When self-update refuses a version that is younger than the cutoff, an interactive run now offers to update anyway; non-interactive runs still fail. CI never prompts, even on a runner that attaches a TTY.

Patch Changes
  • Fixed pnpm licenses list to report every version when the same package is installed under multiple aliases pnpm/pnpm#13438.

  • Sort pnpm dedupe --check snapshot changes for stable output across pnpm implementations.

  • Strip Unicode formatting characters from registry- and manifest-derived terminal output.

  • Speed up installs after compatible catalog or direct dependency range changes by retaining the locked version without resolving the dependency graph again.

  • Speed up installs after safe override changes by reusing unambiguous compatible dependency resolutions, pruning obsolete dependencies, applying independent replacements and removals together, and handling parent-scoped "-" overrides without full lockfile resolution.

  • Installing a local file: directory dependency with the global virtual store enabled no longer fails with TypeError: Cannot read properties of undefined (reading 'split') #​13335.

    Local directory dependencies — file: directories and injected workspace packages — now get a global-virtual-store slot of their own per project. They used to share one slot across every project that depended on a directory of the same name, so a project could end up linked to another project's copy of the dependency.

  • The Workspace column of pnpm update --interactive now falls back to the project's path when its name is only whitespace, as it already did for a missing or empty one — all three render an equally blank label otherwise.

  • Checking GitHub Actions dependencies for updates is now opt-in for every command. Neither pnpm outdated nor pnpm update reads the workflow files unless --include-github-actions is passed or update.githubActions is set to true in pnpm-workspace.yaml. Reading them runs git ls-remote against every referenced repository, which fails in environments where GitHub is not reachable the way pnpm assumes (a GitHub Enterprise Server, a custom certificate authority, or an offline network) #​13254.

    pnpm outdated accepts the --include-github-actions option too.

  • pnpm update --interactive now measures its table in terminal columns rather than in characters. A package name, workspace name, or version containing wide characters (CJK, most emoji) no longer knocks its row's columns out of line with the rest of the group, and a wide character in a version no longer aborts the command with Subject parameter value width cannot be greater than the container width #​13357.

  • The Workspace column of pnpm update --interactive is more informative in two cases. A dependency outdated at the same version in several workspace projects is offered as one choice, since selecting it updates every project — that choice now names all of them instead of only the first. And a workspace project without a name is now labelled with its path rather than left blank, so several unnamed projects can be told apart.

  • An auto-installed optional peer is no longer hoisted at a version the workspace root's own dependency on that package excludes. resolvePeersFromWorkspaceRoot already made the workspace root's specifier decide which version a missing required peer is installed at; the optional-peer picker ignored it and always took the highest version present anywhere in the graph. In a workspace whose root pins postcss: 8.5.10, an importer that depends on webpack and declares no postcss of its own got postcss@8.5.22 hoisted for terser-webpack-plugin's optional postcss peer, leaving two postcss@8.5.x instances in the graph #​13320.

  • overrides now also govern peers that pnpm auto-installs. Previously an override only rewrote dependencies declared in a manifest, so a peer nobody declares — installed because autoInstallPeers is on — resolved against its declared peer range and could bring in a second copy of the very package the override pinned. For example, with overrides: { react: npm:react@19.2.0 } and a lone lucide-react dependency, pnpm installed react@18.3.1; it now installs the pinned react@19.2.0 #​13320.

  • Under resolvePeersFromWorkspaceRoot, a workspace root dependency declared with link: or file: (or the path form of workspace:, such as workspace:../pkg) now satisfies another project's missing peer dependency at the linked package's own version, instead of being hoisted as a path. Those specifiers are relative to the project that declares them, so the same specifier reached a different directory — or none — from the project the peer was hoisted into, leaving a broken link. The root now has the same authority over the peer as it has when it declares the package with a version range #​13373.

  • Installs through a pnpr server now apply the project's whole verification policy. minimumReleaseAgeExclude, minimumReleaseAgeIgnoreMissingTime, trustPolicy, trustPolicyExclude, trustPolicyIgnoreAfter, and trustLockfile were ignored, so excluded packages were still held back and a lockfile containing them could be rejected.

    trustPolicy: no-downgrade no longer fails with TRUST_POLICY_INCOMPATIBLE_WITH_PNPR when a pnpr server is configured.

    --frozen-lockfile and --no-prefer-frozen-lockfile are now honored on the pnpr path, instead of resolving and rewriting the lockfile anyway. Since frozenLockfile defaults to true on CI, a CI install through a pnpr server now fails on an out-of-date lockfile rather than updating it.

  • Workspace installs through a pnpr server no longer crash with Cannot read properties of undefined (reading 'filter') after linking, when minimumReleaseAge is active #​13275.

  • Fixed pnpm dedupe updating valid catalog resolutions when another matching version exists in the lockfile.

  • pnpm -r run "/pattern/" --no-bail no longer exits zero when one of a project's matched scripts fails and a later one passes. The run summary carries a single status per project, and the passing script overwrote the recorded failure.

  • Restored the store block a first install prints, naming how packages were materialized and where the stores live #​13315:

    Packages are hard linked from the content-addressable store to the virtual store.
      Content-addressable store is at: ~/.local/share/pnpm/store/v11
      Virtual store is at:             node_modules/.pnpm
    
  • The root project's pnpm:devPreinstall script now runs before resolution and linking, as it does in pnpm 11. It is skipped under --ignore-scripts, --lockfile-only and --dry-run, by pnpm fetch and pnpm rebuild, and by a repeat install that is already up to date. Workspaces that use the hook to prepare state the install depends on — such as next.js, which generates a placeholder next bin with it — were left with dependents linked against files that were never created #​13313.

  • Prevented pnpm dedupe --check from removing an incompatible node_modules directory.

  • pnpm update --workspace no longer links dependencies the user never named:

    • Running it with updateConfig.ignoreDependencies configured no longer fails with ERR_PNPM_WORKSPACE_PACKAGE_NOT_FOUND for a dependency that is only published to the registry. Such dependencies keep their specifiers, as they already did when no dependencies were ignored.
    • Passing package selectors that match no direct dependency no longer falls back to linking every workspace dependency.
Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.17.0: pnpm 11.17

Compare Source

Minor Changes
  • Added a new setting, update.githubActionsServer, for specifying the base URL of the GitHub server that hosts the repositories of the GitHub Actions referenced by the workflow files (for example, a GitHub Enterprise Server). When the setting is not defined, the URL is read from the GITHUB_SERVER_URL environment variable, falling back to https://github.com. The URL must use the https:// or http:// protocol #​13220.

    pnpm outdated and pnpm update no longer fail when the refs of a GitHub Action's repository cannot be read (for example, when the action's repository is private or hosted on a different GitHub server). Such actions are now skipped with a warning.

    Setting update.githubActions to false now makes pnpm outdated and the interactive pnpm update skip GitHub Actions dependencies.

Patch Changes
  • The token poll for web-based authentication no longer reads the body of non-OK or still-pending (HTTP 202) responses, and caps the token response body it does read at 64 KiB, so a malicious or compromised registry cannot exhaust memory through the poll pnpm/pnpm#12721.

  • Fixed catalog: references in dependencies and overrides failing to resolve when installing through a pnpr server, which errored with "No catalog entry '' was found for catalog 'default'." even though the catalog entry existed. Also fixed a crash on Windows when installing a nested workspace member (e.g. packages/foo) through a pnpr server #​13232.

  • Republished every package: the tarballs published by the v11.13.1 through v11.16.0 releases were missing most of their compiled files due to a packing bug #​13164.

  • Revert script ordering change for pnpm run --sequential /regex/

  • Support the from-git argument in the pnpm version command.

  • When the authentication URL cannot be rendered as a QR code (for example when it exceeds the maximum QR data capacity), web-based login now displays the URL alone with a warning instead of aborting authentication pnpm/pnpm#12721.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.16.0: pnpm 11.16

Compare Source

Minor Changes
  • The first release of a package now publishes the version written in its manifest verbatim, instead of bumping off it. pnpm version -r and pnpm change status check the registry for each release's current version; when that version is not yet published, the package debuts at it and its pending changesets apply only from the next release. A newly added package seeded at 1100.0.0 with a minor changeset is therefore published as 1100.0.0 rather than skipping straight to 1100.1.0.

  • Added a --changeset flag to pnpm update. Set update.changeset to true in pnpm-workspace.yaml to enable this behavior by default, and use --no-changeset to override the setting for one update. After the update completes, pnpm writes a .changeset/pnpm-update-<suffix>.md file declaring a patch bump for every workspace package whose dependencies or optionalDependencies were changed by the update and a major bump when peerDependencies changed, including packages that consume an updated catalog entry via the catalog: protocol. Private packages, packages without a name, and packages listed in the ignore array of .changeset/config.json are skipped. If .changeset/config.json does not exist, a warning is printed and no changeset is generated.

  • Added GitHub Actions dependencies to pnpm outdated and interactive pnpm update. Non-interactive updates can include them with --include-github-actions or by setting update.githubActions to true in pnpm-workspace.yaml. Updated actions are pinned to exact commit hashes with their release tags preserved in comments.

  • Added update and audit settings sections to pnpm-workspace.yaml, superseding the awkwardly named updateConfig, auditConfig, and top-level auditLevel settings:

    update:
      ignoreDeps: # was updateConfig.ignoreDependencies
        - webpack
        - "@babel/*"
    
    audit:
      level: high # was auditLevel
      ignore: # was auditConfig.ignoreGhsas
        - GHSA-xxxx-yyyy-zzzz
    

    update.ignoreDeps lists dependency name patterns that pnpm update and pnpm outdated should skip. audit.level and audit.ignore tune pnpm audit.

    The deprecated updateConfig, auditConfig, and auditLevel settings keep working until the next major version. When both a new section value and its deprecated counterpart are set, the new section takes precedence and a warning is printed. Both the TypeScript CLI and the Rust config surface (pacquet) recognize the new sections.

Patch Changes
  • Fixed pnpm add --save-exact/--save-prefix and pnpm update writing a package's version with the peerDependencies range's prefix (e.g. ^19.2.7 instead of the requested 19.2.7) whenever the same package also appeared in peerDependencies. A real dependencies/devDependencies/optionalDependencies entry now takes precedence over a same-named peerDependencies entry when computing the current specifiers #​13108.
Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.15.1: pnpm 11.15.1

Compare Source

Patch Changes
  • pnpm install now detects a supportedArchitectures change and re-evaluates previously skipped platform-specific optional dependencies, instead of reporting the project as up to date and leaving the packages for the old architecture set in place.

  • pnpm setup now removes leftover v10-layout shims at the top of PNPM_HOME, so pnpm self-update no longer warns about a v10 installation layout after PATH has been migrated to the v11 PNPM_HOME/bin layout. Applies to both the TypeScript CLI and pacquet.

    In the TypeScript CLI, self-update also no longer treats a dangling legacy shim (one whose install target was garbage-collected) as a real v10 layout, so the warning can no longer fire on dead shim files.

    Closes #​12496.

  • Completed pnpm runtime installation parity for Node.js, Deno, and Bun, including runtime failure policy, target architecture selection, and dependency runtime engines. Runtime failure overrides now preserve explicit runtime dependencies without matching engine entries.

  • Fixed pnpm install running out of memory while resolving large dependency graphs #​8441. The resolver kept full registry documents — per-version readmes, scripts, descriptions, and other install-irrelevant bulk — in memory for every package fetched with full metadata (optional dependencies, and packages re-fetched for minimumReleaseAge's publish timestamps). Every retained document is now condensed down to the field set installation actually reads, which reduces peak resolution memory by several times on workspaces with more than a thousand packages.

  • When a dependency's build script fails under enableGlobalVirtualStore, the global virtual store directory it was being built in is now removed for scoped packages too. Previously the cleanup resolved one directory level short of the hash directory for a scoped name, leaving a half-built directory behind that later installs would reuse.

  • Fixed pnpm login, pnpm adduser, and pnpm logout against a registry hosted under a URL subpath (e.g. https://example.com/npm/registry) when the configured URL has no trailing slash. Such URLs were left unnormalized, so the last path segment was dropped when building the login and token endpoints and the auth token was stored under a truncated key. Registry URLs with a path now always get a trailing slash appended during normalization, matching how root-level registry URLs are handled.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.15.0: pnpm 11.15

Compare Source

Minor Changes
  • Optional peer dependencies declared only via peerDependenciesMeta (for example debug's supports-color peer) are now resolved from a satisfying version already present in the dependency graph, the same way explicitly declared optional peer dependencies are. Previously such peers were only resolved this way when the package's metadata was read back from the lockfile, so an unrelated dependency change could rewrite peer resolutions across the whole lockfile.
Patch Changes
  • Updated adm-zip to prevent crafted ZIP archives from causing excessive memory allocation.

  • pnpm version -r no longer writes a versioning-ledger entry with no consumed intents as a bare intents: key, which the next run failed to read with ERR_PNPM_INVALID_VERSIONING_LEDGER. Empty intent lists are now written as intents: [], and the ledger reader accepts the bare form left by earlier releases.

  • Fixed pnpr workspace resolution to preserve project names and versions for workspace: dependencies.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.14.0: pnpm 11.14

Compare Source

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

  • Added pnpm doctor, which diagnoses the pnpm installation and the environment it runs in: the versions and install method, whether the global bin directory is on PATH, whether the store and cache are writable, which link strategies (reflink, hardlink, symlink) the store's filesystem supports, registry connectivity, and an offline file: install that exercises the resolve/store/link path end to end. Each check reports how to fix what it finds, and the command exits non-zero when any check fails.

    Use --offline to skip the checks that need network access, --json for machine-readable output, and --benchmark to time the filesystem and install checks.

  • Added support for executing multiple scripts matching a RegExp passed to pnpm run (e.g., pnpm run "/^build:.*/"), running matched scripts in deterministic lexicographical order. Restored the --sequential (-s) CLI option for pnpm run, which forces workspaceConcurrency to 1 so that matched scripts run sequentially one by one across and within packages.

Patch Changes
  • Fixed pnpm install failing with ERR_PNPM_LOCKFILE_IS_SYMLINK when pnpm-lock.yaml is a symlink, as build sandboxes such as Bazel and Nix stage it #​13073. Reading a lockfile through a symlink is allowed again, and an install that leaves the lockfile unchanged no longer rewrites it, so --frozen-lockfile no longer needs to write at all. Writing a changed lockfile through a symlink is still refused, as that would redirect the write onto the symlink's target.

  • Fixed frozen installs incorrectly treating equivalent Git dependency specifiers as a stale lockfile. See #​13039.

  • pnpm owner ls now reports authentication and authorization failures (401/403) as dedicated errors that include the registry's response body, matching pnpm owner add/rm, instead of a generic Failed to fetch owners message.

  • Recover from a metadata cache entry that disappears (concurrent cache cleanup, antivirus) after the registry has already answered the conditional request with 304 Not Modified. The metadata is re-requested once without cache validators instead of failing the install with ERR_PNPM_CACHE_MISSING_AFTER_304.

  • A project pinned to a broken pnpm release via packageManager or devEngines.packageManager now reports which release is broken and what to do about it, instead of failing inside the installer. pnpm self-update already refused these releases; the version switch does too.

  • Prevent broken-lockfile errors from including snippets of the lockfile's contents.

  • pnpm self-update now checks that the version it installed can run before making it the active pnpm. A release that installs but cannot execute is discarded with an error instead of replacing a working installation.

  • Fixed an out-of-memory regression when workspace projects concurrently resolve a package with large registry metadata pnpm/pnpm#13077.

  • Fixed pnpm update rewriting exact version pins that use the = operator (for example =3.5.1) to a caret range (^3.5.1). Exact pins are now preserved and written back as the bare version. See #​12745.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.13.1: pnpm 11.13.1

Compare Source

Patch Changes
  • Fixed pnpm pack applying workspace-root ignore rules when a workspace package has its own .npmignore file.
  • Keep the interactive minimumReleaseAge approval prompt visible during pnpm install. The progress reporter now pauses its redraws while a prompt is waiting for input instead of overwriting it, so the install no longer hangs on a question the user cannot see #​13019.
  • Fixed pnpm self-update failing to link native platform binaries stored in sibling global virtual store slots.

v11.13.0: pnpm 11.13

Compare Source

Minor Changes
  • Added versioning.epics to pnpm-workspace.yaml. An epic ties a group of member packages to a lead package, constraining every member's major version to a band derived from the lead's major: while the lead is on major M, members live in M*100 … M*100+99. Members move independently inside the band (patch, minor, and a major intent that stays in-band); a bump that would carry a member past the band ceiling is rejected until the lead advances its own major. When a release plan takes the lead to a new stable major, every member re-bases to the band floor in the same plan. Membership is matched with pnpm's package selectors — name globs, ./-prefixed directory globs, and !-prefixed negations.

  • Added the team command for managing organization teams and team memberships on the registry, with create, destroy, add, rm, and ls subcommands and support for --otp, --parseable, and --json flags.

  • Added native workspace release management #​12952: the new pnpm change command records change intents as changesets-compatible .changeset/*.md files (pnpm change status shows the pending release plan), and the bare pnpm version -r consumes them — bumping versions across the workspace with dependent propagation through workspace: ranges, fixed groups, a maxBump cap, --filter narrowing, and --dry-run — writing changelogs, and recording consumed intents in a committed ledger that keeps cherry-picks and merge-backs between release branches safe. Packages can be moved onto per-package release lanes with the new pnpm lane <name> --filter <pkg> command and back with pnpm lane main --filter <pkg> (pnpm lane shows the membership), releasing X.Y.Z-lane.N prereleases from the same runs that release stable versions of the packages on the main lane. Configuration lives under the new versioning key of pnpm-workspace.yaml (fixed, ignore, maxBump, lanes, changelog). When two workspace projects publish the same name, intent files, versioning.lanes, and versioning.fixed/ignore may reference a project by its workspace-relative directory path (e.g. "./pnpm/npm/pnpm") — the one additive extension to the changesets format, applied automatically by pnpm change.

    Release changelogs default to registry storage (versioning.changelog.storage): no CHANGELOG.md is committed. Each release's section is composed at publish time and packed into the published tarball on top of the previously published version's changelog, and the consumed change intents are garbage-collected by a later pnpm version -r only once the registry confirms the version is published with its section. Set versioning.changelog.storage: repository to keep committed CHANGELOG.md files instead.

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

    overrides:
      "form-data@": 4.0.6
    

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

Patch Changes
  • A tokenHelper set in the global pnpm auth.ini is no longer rejected as project-level configuration. The guard that blocks tokenHelper from a project .npmrc only treated ~/.npmrc as a trusted source, so a helper written to auth.ini (for example by pnpm config set) failed on every command and could not even be removed with pnpm config delete. A tokenHelper in a workspace or project .npmrc is still rejected.

  • pnpm cache delete now removes a package's metadata from every metadata cache directory (metadata, metadata-full, and metadata-full-filtered), instead of only the one the current resolution mode reads. Previously a package cached under a different mode (e.g. metadata-full-filtered) was left behind. Closes #​12753.

  • Fixed an injected workspace dependency (injectWorkspacePackages: true) incorrectly staying as file: instead of deduping back to link: when an unrelated, ordinary shared dependency resolved to a peer-suffixed variant for the target project's own copy but not for the injected occurrence. See #​10433.

  • pnpm deploy now supports workspaces that use catalogs.

  • Fixed pnpm deploy with a shared lockfile so local file: tarball dependencies keep their package name in the generated deploy lockfile. This prevents warm-store deploys from failing with ERR_PNPM_UNEXPECTED_PKG_CONTENT_IN_STORE when the tarball filename includes the version.

  • Options that follow create, exec, or test appearing as a subcommand of another command are now parsed instead of being silently treated as positional parameters. For example, pnpm team create @org:team --registry <url> previously ignored the --registry option and sent the request to the default registry.

  • pnpm add -g, pnpm update -g, pnpm setup, and the self-updater no longer fail with ERR_PNPM_MISSING_TIME when trustPolicy: no-downgrade or resolutionMode: time-based is set in the global config #​12883. The decision to fetch full registry metadata now lives in one place, and the no-downgrade trust policy always requests full metadata (matching the self-updater), since the trust evidence it checks is missing from abbreviated metadata even on registries that include the time field.

  • pnpm list and pnpm why no longer crash with EMFILE: too many open files when a project has a large number of unsaved dependencies (packages present in node_modules but not in the lockfile). The reads of those packages are now concurrency-limited.

  • The published pnpm package no longer declares dependencies or devDependencies. Because the CLI bundles its runtime dependencies into dist/node_modules, those fields are dropped when packing, so npm install of the tarball no longer tries to resolve internal-only packages such as @pnpm/test-ipc-server. Closes #​12955.

  • Fixed pnpm publish --otp and pnpm publish --batch --otp to send the configured OTP to the registry.

  • pnpm publish again sends the package's README to the registry as metadata, so registries can render it on the package page. The readme is always included in the published metadata (matching the npm CLI), while the embed-readme setting continues to control only whether the readme is written into the package.json inside the tarball. This restores the behavior that was lost when publishing became fully native. Closes #​12966.

  • Fixed the dependency status check wrongly reporting "up to date" when a package.json, .pnpmfile.cjs, or patch file was edited in the same second as the previous install, on filesystems that record mtimes at whole-second resolution (for example ext4 with 128-byte inodes). The optimistic repeat-install fast path and verify-deps-before-run compared mtimes strictly, so a same-second edit whose mtime rounded down looked unchanged and re-resolution was skipped. Such a file's whole second is now treated as possibly-modified, falling through to the content check; behavior on sub-second filesystems is unchanged.

  • Retry package metadata requests when a registry or proxy returns 304 Not Modified to an unconditional request, preventing false ERR_PNPM_CACHE_MISSING_AFTER_304 failures pnpm/pnpm#12882.

    If the retry also returns 304, report ERR_PNPM_META_NOT_MODIFIED_WITHOUT_CACHE instead.

  • Fixed pnpm update removing transitive lockfile entries when dedupePeerDependents is disabled and the selected package is absent pnpm/pnpm#12456.

  • Limit modern deploy lockfiles and localized virtual stores to dependencies reachable from the selected dependency groups.

  • A tokenHelper command is now given a 60-second time limit. A helper that hangs (deadlock, stuck I/O) is killed and reported as an error instead of leaving the command waiting forever.

  • Fixed orphaned child processes on Windows when pnpm exits on an error while commands spawned by pnpm exec or pnpm dlx are still running (for example, when one project's command fails during pnpm --recursive exec). The PIDs of these commands are now recorded when they are spawned and their whole process trees are terminated with taskkill on an error exit. Previously the cleanup relied on enumerating the system process list, which is so slow on Windows that the enumeration hit its timeout and the cleanup was silently skipped #​12406.

  • pnpm pack now respects workspace-root .npmignore and .gitignore files when packing workspace packages.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.12.0: pnpm 11.12

Compare Source

Minor Changes
  • a897ef7: Custom fetchers exported from a pnpmfile can now delegate by returning a { delegate: <resolution> } envelope: pnpm rewrites the package's resolution to the delegated shape and runs the built-in fetcher on it. This is the portable delegation form that also works in pacquet, where cafs and fetchers cannot be passed to the hook. Related to pnpm/pnpm#11685.
Patch Changes
  • 2b02764: The changed-packages filter (--filter "...[<since>]") no longer allows an option-like <since> value (such as --output=<path>) to be interpreted as a git option — git now rejects it as a bad revision. The repository root is also resolved to the nearest .git entry, so the filter works in a git worktree checked out inside another repository's tree.

  • 43711ce: pnpm outdated no longer checks the registry for dependencies that are resolved from local link:, file:, or workspace: references in the lockfile #​12827.

  • 3c6718b: Fixed a deadlock in peer dependency resolution: pnpm install hung forever when a peer dependency cycle spanned a project's own dependencies and auto-installed peer providers, for example when installing electron-builder@26.15.3 #​12921.

  • 252f15e: Fixed peer dependency auto-install picking a version the peer range rejects. In a workspace with several projects, a package declaring a peer dependency with a semver range (for example ^1.0.0) could get the highest version found anywhere in the workspace (for example a 2.0.0 resolved for another project) instead of a version that satisfies the range. Peers are now deduplicated onto the highest preferred version that satisfies the declared range, and when none does, the range is resolved from the registry.

    Also fixed re-resolving with an existing lockfile hoisting a different peer version than a fresh install of the same manifest: root dependencies reused from the lockfile were invisible to peer hoisting, so a peer that a root dependency provides could be bound to another version.

  • a38adda: pnpm self-update <version> now installs the requested pnpm version when it matches the currently running version but is missing from the global self-update directory.

  • 6a85968: pnpm stage list now stops paginating after a fail-safe cap of 1000 pages, so a misbehaving registry cannot keep the command looping forever.

  • eee7c9a: verify-deps-before-run no longer spawns a pnpm install when pnpm is executed in a directory that has no package.json. A mistyped command run outside a project (for example pnpm witch 10 login) used to crash with a confusing error from the spawned install; now it fails with the regular "no package.json found" error.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.11.0: pnpm 11.11

Compare Source

Minor Changes
  • 508b8c2: Added the pnpm access command for managing package access and visibility on the registry, supporting listing packages and collaborators, getting and setting package status and MFA requirements, and granting or revoking team access.
Patch Changes
  • c70e33e: Allow allowBuilds entries for git-hosted packages to match by repository URL without pinning the resolved commit hash. This lets trusted git repositories keep running their build scripts after branch updates without approving each new commit, while package-name-only rules still do not approve git-hosted artifacts.
  • 3067e4f: Reduced peak memory usage during cold-cache dependency resolution. The metadata fetch is memoized for the whole resolution phase, and it was retaining each package's raw registry response body (used only to mirror the response to disk) for that entire time. The memoized cache now holds a body-less copy, so the raw body only lives as long as the call that writes the disk mirror. On large graphs that fetch full metadata (e.g. with minimumReleaseAge or trustPolicy enabled) this cuts peak RSS by roughly 30%, back in line with pnpm 10. The resolved lockfile is unchanged.
  • 51300fd: Prevent a crafted pnpm-lock.yaml from writing package content outside the virtual store. A dependency path key whose name reconstructs to a path-traversal sequence (e.g. ../../../tmp/x@1.0.0) is now rejected by the isolated (virtual-store) linker and the Plug'n'Play resolver map, matching the containment already applied to the hoisted linker. Under the global virtual store, a traversal in the version-derived path segment (e.g. a snapshot version: "../../x") is now rejected at formatGlobalVirtualStorePath, the single point every global-virtual-store slot path funnels through — closing the same escape in the isolated linker, the resolver's dependency-graph builder, and the config-dependency installer.
  • f8058eb: Reject symlinked pnpm-lock.yaml files when reading or writing the env lockfile document.
  • 9318a11: Allow registries and namedRegistries to be configured in the global config.yaml file.
  • 51300fd: Fixed a path traversal vulnerability where a dependency whose manifest name was a scoped path traversal (e.g. @x/../../../<path>) could be written outside node_modules to an attacker-controlled location during pnpm install, even with --ignore-scripts. The isolated linker now validates the package name before using it as a directory name, matching the existing protection in the hoisted linker.
  • 14332f0: Fail instead of silently removing an optional dependency's locked entries from pnpm-lock.yaml when the registry cannot resolve it. Previously, when registry metadata lacked a version that the lockfile already pinned (for example, a mirror that had not synced a recent release yet), pnpm install and pnpm dedupe silently dropped the optional dependency's entries — emptying maps such as the platform binaries of @napi-rs/canvas — so the lockfile differed between machines and frozen installs on other hosts had nothing to link #​12853.
  • fecfe83: Fixed peer dependency resolution with autoInstallPeers when a workspace package depends on a version of a package that a transitive dependency's self-contained closure also provides for itself. The peer providers that are attached to the root project for reuse are no longer peer-resolved a second time in the root context, so packages inside such a closure no longer get their peers bound to the root project's incompatible version #​4993.
  • 5a4daec: ${...} environment-variable placeholders in the httpProxy, httpsProxy, noProxy, proxy, and noproxy settings are no longer expanded when these settings come from a project's pnpm-workspace.yaml. They now receive the same protection already applied to registry, namedRegistries, and pnprServer.
  • d1da02e: pnpm publish no longer prints credentials when the target registry is configured with inline user:pass@ credentials (e.g. registry=https://user:pass@example.com/). They are now redacted both from the "publishing to registry" line and from the OIDC (trusted publishing) failure messages.
  • dcfc611: pnpm self-update now honors trustPolicy=no-downgrade. It resolves the target pnpm version against full registry metadata, so it refuses to switch to a version whose supply-chain trust evidence is weaker than an earlier-published one, the same way a regular install does.
  • a8ad82d: Register the pn alias in generated shell completion scripts.
  • 25bd5c3: Fixed standalone installer downgrades from pnpm v12 to v11.
  • 23996e9: pnpm runtime set <name> <version> now validates its arguments: the name must be node, deno, or bun, and the version must not contain a comma. Previously these were interpolated straight into a pnpm add selector, where an unsupported name or a comma (e.g. node 22,is-positive) could be misread as a list of packages or a local directory and install unintended packages or bins.
Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.10.0: pnpm 11.10

Compare Source

Minor Changes
  • e2e3c81: Added the issues command as an alias of bugs, so pnpm issues opens the package's bug tracker URL in the browser.

  • 8491f8e: Added the prefix command which prints the current package prefix directory (or global prefix directory if -g / --global is used).

  • 3425e80: Added an _auth setting for configuring registry authentication as a single structured (URL-keyed) value. It can be set in the global pnpm config (config.yaml) or, for CI, via the pnpm_config__auth environment variable. The env form sidesteps the GitHub Actions / bash / zsh limitation that broke the existing pnpm_config_//host/:_authToken=… form (env var names containing /, :, or . are silently dropped). Closes #​12314.

    The value is keyed by registry URL so each secret is explicitly bound to the host that may receive it. Registry URL keys must use http or https and must not include credentials, query strings, or fragments:

    export pnpm_config__auth='{"https://registry.npmjs.org":{"@":{"authToken":"npm-token"},"@org":{"authToken":"org-token"}}}'
    

    The equivalent in the global config.yaml:

    _auth:
      https://registry.npmjs.org:
        "@":
          authToken: npm-token
        "@org":
          authToken: org-token
    

    Within each registry URL, @ means registry-wide/default credentials and package scopes like @org bind credentials to that scope on the same host. The only supported credential field is authToken (maps to _authToken / bearer auth); the deprecated basicAuth / username + password forms are intentionally not accepted here.

    Each entry also infers a trusted registry route: @ routes the default registry (and pnpm add <pkg> resolves there), and @org routes that scope. Because the credential and destination host arrive in one trusted value, repo-controlled pnpm-workspace.yaml or project .npmrc cannot redirect the token to a different host. _auth is honored only from the env var and the global config — it is ignored in a project pnpm-workspace.yaml / .npmrc, so repo-controlled config can never supply registry auth. Precedence: CLI flags (--registry, --@scope:registry) > pnpm_config__auth > global config.yaml _auth > pnpm-workspace.yaml.

    Both pnpm_config__auth (lowercase, documented form) and PNPM_CONFIG__AUTH (all-caps, the shell convention some CI runners apply) are honored. If both are set, lowercase wins unless it is empty, in which case uppercase is used. The env var wins over the global config.yaml _auth on a conflicting key. tokenHelper is not supported in _auth. Parsing is strict: a malformed value (bad JSON, wrong shape, invalid registry URL or scope, an unsupported credential field) fails fast with an error rather than being silently dropped.

    Pacquet parity note: the pacquet (Rust) port supports the same single credential field as the TS CLI: authToken.

  • a33eeec: pnpm self-update and packageManager version-switching can now install and link pnpm v12 (the Rust port), published with equal content under both the pnpm and @pnpm/exe names on the next-12 dist-tag. Its native binaries ship as @pnpm/exe.<platform>-<arch> packages, which pnpm's built-in installer links directly — no Node.js launcher, so the command pays no Node startup cost. v12 is initialized exactly like @pnpm/exe, including per-platform global-virtual-store hashing. From v12 onward the install converges on the unscoped pnpm package (the Rust exe) — even when updating from the SEA @pnpm/exe build.

  • 1dd12bd: When resolving through a pnpr install-accelerator server, pnpm no longer forwards its own upstream registry credentials in the resolve request. Only the Authorization header identifying the caller to pnpr is sent. The pnpr server now selects upstream credentials from its own route policy (operator-configured upstream credential aliases), so private dependencies resolve through a pnpr-managed alias the caller is authorized to use, rather than by sending the client's registry tokens to the server.

  • 1e81761: Expose web authentication authUrl and doneUrl in JSON error output when OTP is required in a non-interactive terminal #​12724.

Patch Changes
  • 2f389d6: Added the Node.js release team's new signing key (Stewart X Addison, 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD) to the embedded Node.js release keys, so runtimes whose SHASUMS256.txt is signed by the new releaser verify successfully.

  • acbdb94: Fixed shell tab completion not suggesting workspaces after the -F alias for --filter option.

  • dcabb78: Fixed pnpm up -r <pkg> bumping unrelated packages that have open semver ranges. Previously, any update mutation nullified the lockfile-derived preferredVersions globally, so packages with ^x.y.z ranges could re-resolve to newer compatible versions even though the user only asked to update a specific package. The install layer now always seeds preferredVersions from the lockfile, and caller-supplied preferred versions (such as the vulnerability penalties of pnpm audit --fix) layer on top of the seed instead of replacing it. The targeted package still bumps: the per-resolve updateRequested flag makes the resolver ignore the target's own lockfile pins.

    Closes #​10662.

  • d539172: Fixed pnpm pack and pnpm publish failing when prepack generates files that are included in the package and postpack cleans them up.

  • be6505a: Hardened global package management:

    • On Windows, removing or updating a global package now also cleans up the node.exe flavor of a bin, so a stale node.exe no longer survives on PATH after uninstall, and a new global install no longer silently overwrites an existing node.exe.
    • pnpm add -g pnpm@<version> (and @pnpm/exe@<version>) is now rejected like the bare pnpm form, pointing to pnpm self-update.
    • Dependency aliases read from a global package's manifest are validated before being joined onto node_modules paths, preventing a tampered manifest from escaping the install directory.
    • Each global install group is created in its own freshly-made directory (no longer reusing a colliding or pre-existing path).
    • Removing or updating a global package no longer unlinks a bin that belongs to a different globally installed package.
  • 25c7388: pnpm now rejects jsr: specifiers whose package name is not a valid npm package name — an empty scope or name (e.g. jsr:@scope/), path separators inside the name, or any other shape validate-npm-package-name rejects — with ERR_PNPM_INVALID_JSR_PACKAGE_NAME instead of silently converting them into a malformed @jsr/... npm package name.

  • 25c7388: pnpm now rejects named-registry specifiers (e.g. gh:) whose package name is not a valid npm package name — an empty scope (e.g. gh:@/bar), path separators inside the name (e.g. gh:@scope/../name), or any other shape validate-npm-package-name rejects — with ERR_PNPM_INVALID_NAMED_REGISTRY_PACKAGE_NAME instead of passing the name through to registry URLs and metadata cache file paths.

  • 96da7c5: node-gyp's gyp_main.py and gyp entrypoints are now packed with the executable bit in the pnpm and @pnpm/exe tarballs. Without it, building native addons from source could fail with a permission error.

  • 99982b9: Sped up resolution and reduced memory use against registries that ignore npm's abbreviated metadata format and always return the full package document (for example, Azure DevOps Artifacts). pnpm now strips such documents down to the abbreviated field set before caching them. Resolution output is unchanged, and registries that honor the abbreviated format (such as the npm registry) pay no extra cost.

  • 11a7fdd: Sped up offline and --prefer-offline resolution on large workspaces (e.g. pnpm dedupe --offline, pnpm install --offline). Package metadata loaded from the local cache is now kept in memory, so each package's metadata is parsed once per command instead of once per dependent that references it.

  • 2c7369d: pnpm pack-app now rejects --entry / pnpm.app.entry and --output-dir / pnpm.app.outputDir values that are absolute paths or escape the project directory via .. (or a symlink that resolves outside it), and refuses to write the produced executable when its target path already exists as a symlink (or other non-regular file). This prevents a repository-controlled package.json from embedding host files (such as an SSH key) into the produced executable, writing build artifacts outside the project, or overwriting an arbitrary file through a committed symlink. The new error codes are ERR_PNPM_PACK_APP_ENTRY_OUTSIDE_PROJECT, ERR_PNPM_PACK_APP_OUTPUT_DIR_OUTSIDE_PROJECT, and ERR_PNPM_PACK_APP_OUTPUT_FILE_NOT_REGULAR.

    When ad-hoc signing macOS targets, pnpm pack-app now runs the system codesign by absolute path and resolves ldid to a location outside the project, so a repository-controlled node_modules/.bin on PATH cannot hijack the signer.

  • ce5d5a5: Relative paths in patchedDependencies are now resolved against the lockfile directory when computing patch file hashes, so running pnpm install from a subdirectory no longer fails with ENOENT looking for the patch file in the wrong location #​12762.

  • ebb4096: pnpm peers no longer reports a conflict for a missing peer dependency that is ignored via pnpm.peerDependencyRules.ignoreMissing.

  • dcabb78: Fixed a prototype-pollution hazard when seeding preferred versions: a dependency named __proto__ in a manifest or in pnpm-lock.yaml could write through Object.prototype (or crash the install) while the preferred-versions map was being built. The maps are now null-prototype objects, so crafted package names land as plain keys.

  • f38e696: Hardened pnpm deploy --force so it refuses unsafe deploy targets such as workspace roots, parent directories, out-of-workspace paths, and symlinked target parents.

  • 806c3ec: pnpm no longer warns about ignored project-level auth settings when PNPM_CONFIG_NPMRC_AUTH_FILE points at the project .npmrc — setting it to that file is an explicit opt-in to trusting it, so auth env variables in it are expanded pnpm/pnpm#12480.

  • 991405e: Restore differential rendering (ansi-diff) to fix duplicated output lines introduced by #​12351.

  • c121235: Fixed the topological order of --filtered commands (pnpm run, pnpm exec, pnpm publish, pnpm pack, pnpm rebuild) when the selected projects depend on each other only transitively through projects that were not selected. Previously such selected projects could run concurrently or in the wrong order; now a project always runs after the selected projects it transitively depends on, while projects without a real dependency relationship still run concurrently. This now also holds for prod-only filters (--filter-prod), which resolve order through the production dependency graph so transitive production dependencies are respected without pulling back the dev dependencies the filter drops, and for selections that mix --filter with --filter-prod #​8335.

  • d539172: pnpm pack and pnpm publish no longer follow a symlinked workspace LICENSE file when injecting it into a package that has no license of its own. Following the symlink could pack bytes from outside the workspace into the published tarball.

  • dcabb78: Fixed pnpm up <pkg> producing a different result than a fresh install of the same manifests would. The resolver now distinguishes updateRequested (true only for packages that match the user's update target) from the broader update flag, and for the targeted package ignores only its own lockfile-derived preferred-version pins — so the target re-resolves exactly as if its lockfile entries were deleted and pnpm install ran. Preferred versions a fresh install applies (manifest pins, versions propagated down the dependency chain, and the vulnerability-avoidance penalties of pnpm audit --fix) stay in effect, so an update never installs duplicate versions that a reinstall from scratch would not reproduce. When a preferred version holds the update target below the newest version its range admits, pnpm now prints a warning explaining that reaching the newer version everywhere requires an override.

  • dcabb78: pnpm update <dep>@<version> now prints a warning when <dep> is only present as a transitive dependency: the requested version cannot be applied there (updates resolve the target the way a fresh install would), and the warning recommends adding the version to pnpm.overrides instead, which is the mechanism that does pin transitive dependencies. Closes #​12744.

  • a6c4d5f: When a dependency cannot be found in the registry (404) or the registry has no matching version, and a workspace project with the same name exists only at non-matching versions, the error now reports the available workspace versions (ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE) instead of the raw registry failure pnpm/pnpm#1379. Other registry failures (authorization, network, server errors) still propagate unchanged. The pacquet (Rust) resolver applies the same behavior.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.9.0: pnpm 11.9

Compare Source

Minor Changes
  • bae694f: Some registries generate tarballs on-demand and cannot provide an integrity checksum in their package metadata. In that case pnpm now computes the integrity from the downloaded tarball and stores it in the lockfile, so the entry is verifiable on subsequent installs instead of being written without an integrity (which would fail the next install). This also applies to --lockfile-only: the tarball is downloaded so its integrity can be computed. A lockfile entry that is still missing its integrity is rejected as a ERR_PNPM_MISSING_TARBALL_INTEGRITY lockfile verification violation (the install fails closed) rather than being silently re-fetched.
  • 6c35a43: Added --exclude-peers to pnpm sbom. With auto-install-peers (the default), peer dependencies resolve into the lockfile and are otherwise indistinguishable from the package's own dependencies. The flag drops peer dependencies (and any transitive subtree reachable only through them) from the SBOM. CycloneDX 1.7 has no scope or relationship that expresses "consumer-provided peer", so omission is the only spec-clean handling. The flag name matches pnpm list --exclude-peers; note the SBOM flag prunes a peer's exclusive subtree, which is stricter than pnpm list (which only hides leaf peers).
Patch Changes
  • 25a829e: pnpm audit --fix now writes a single combined minimumReleaseAgeExclude entry per package (e.g. axios@0.18.1 || 0.21.1) instead of one entry per version, matching the format documented for the setting. Existing per-version entries in pnpm-workspace.yaml are merged into the combined form rather than left as duplicates. Installs that auto-collect immature versions into minimumReleaseAgeExclude now report the same combined entries, so the "Added N entries" message matches what is written to the manifest #​12534.

  • 1cbb5f2: Fixed non-deterministic peer resolution that could add or remove an optional transitive peer — for example @babel/core, reached through styled-jsx — from a package's peer-dependency suffix across otherwise identical installs, churning the lockfile and causing intermittent pnpm dedupe --check failures in CI. When a package's children are resolved by one occurrence (the "owner") and reused by a deeper consumer, whether that consumer inherited the owner's missing peers depended on whether the owner's resolution had finished yet — a race under concurrent resolution. The decision is now a function of the dependency graph's structure rather than resolution-completion order.

  • d577eea: Fixed a Windows flakiness in pnpm dlx where a failed install could surface a spurious EBUSY: resource busy or locked error. The cleanup of a partially-populated dlx cache is now best-effort with retries and no longer masks the original error.

  • ec7cf70: Shortened the pnpm dlx cache path so deep dependency trees no longer overflow Windows' MAX_PATH, which could make a dependency's lifecycle script fail with spawn cmd.exe ENOENT.

  • 05b95ab: Fixed pnpm hanging (and crashing with an unhandled promise rejection) when a non-retryable network error such as SELF_SIGNED_CERT_IN_CHAIN occurs while fetching from a registry. The error is now rejected through the returned promise instead of being thrown inside the detached retry callback.

  • d3f68e2: Fix a pnpm audit performance regression on lockfiles that contain dependency cycles. The reachable-vulnerability pruning added in pnpm 11.5.1 only memoized acyclic subtrees, so any node whose subtree touched a cycle — together with all of its ancestors — was recomputed on every query, making the path walk quadratic. Reachability is now computed once per node using Tarjan's strongly-connected-components algorithm, so cyclic graphs are handled in linear time #​12212.

    The audit path walk also no longer recurses, so a deeply nested dependency graph can no longer overflow the call stack, and the install path to each finding is tracked without per-node copying, keeping memory linear in the graph depth.

  • 322f88f: Fix failed optional dependency updates so they don't rewrite unrelated dependency specs #​11267.

  • 1488db1: When enableGlobalVirtualStore is toggled on for a project that was previously installed without it, stale hoisted symlinks under node_modules/.pnpm/node_modules are now replaced instead of being left pointing at the old per-project virtual store location #​9739.

  • 6545793: Fixed pnpm install --ignore-workspace overwriting the allowBuilds map in pnpm-workspace.yaml. The ignored builds of a package with a build script were auto-populated into allowBuilds even though --ignore-workspace was passed, clobbering committed true/false values with the set this to true or false placeholder #​12469.

  • fbdc0eb: Fixed minimumReleaseAgeExclude and trustPolicyExclude so multiple exact-version entries for the same package behave the same as a single || disjunction entry. Previously only the first matching rule's versions were honored, so a config like [form-data@4.0.6, form-data@2.5.6] could still flag form-data@2.5.6 as violating minimumReleaseAge, while [form-data@4.0.6 || 2.5.6] worked as expected #​12463.

  • fa7004b: The in-memory package metadata cache is now populated on the exact-version disk fast path, so repeated resolutions of the same package within one install no longer re-read and re-parse the on-disk metadata. In large monorepos this brings the time for adding a new package down from minutes to seconds. The in-memory cache key now also includes the registry, so a package of the same name served by two different registries in a single install can no longer share a cache slot and resolve the wrong tarball.

  • 0a154b1: Fixed pnpm patch dropping the package name (and leaking internal option fields) when the patched dependency resolves to a single git-hosted version.

  • 4d3fe4b: The pnpr resolver endpoints moved under the reserved /-/pnpr namespace: POST /v1/resolve is now POST /-/pnpr/v0/resolve and POST /v1/verify-lockfile is now POST /-/pnpr/v0/verify-lockfile. The capability handshake at GET /-/pnpr advertises protocol version 0 to match. This keeps every pnpr-proprietary route in npm's reserved namespace, so it can never collide with a package path.

  • 0ec878d: Removing a runtime dependency now removes the matching devEngines.runtime or engines.runtime entry that was materialized from it. Blank runtime selectors are normalized to latest.

  • 17e7f2c: pnpm sbom now emits a CycloneDX issue-tracker external reference for components (and the root) whose package.json declares a bugs URL. Email-only bugs entries are skipped, since the reference requires a URL.

  • a84d2a1: Add @pnpm/resolving.tarball-url, which builds and recognizes the canonical npm tarball URL of a package. It vendors getNpmTarballUrl (previously the external get-npm-tarball-url package) and adds isCanonicalRegistryTarballUrl, the predicate the lockfile writer uses to decide whether a tarball URL is derivable from name+version+registry (and can therefore be omitted from pnpm-lock.yaml).

    Exposing isCanonicalRegistryTarballUrl lets a custom resolver (pnpmfile resolvers) fronting a proxy that serves tarballs on a non-canonical path (e.g. an ephemeral localhost:<port>) rewrite the resolved tarball to the canonical form, so nothing host-specific is persisted to the lockfile. Previously this logic was private to @pnpm/lockfile.utils.

    Two correctness fixes are included while consolidating the logic: the scoped-package unescape now handles uppercase %2F as well as %2f (percent-encoding is case-insensitive), and protocol-insensitive comparison strips only a leading http(s):// scheme instead of splitting on the first :// (which could truncate URLs containing a later ://).

  • 852d537: Lockfile verification no longer reports a registry metadata fetch failure (for example a 403/401 on a private registry, or a network error) as ERR_PNPM_TARBALL_URL_MISMATCH. When the registry can't be reached to verify an entry, the install now aborts with the registry's own fetch error (such as ERR_PNPM_FETCH_403, which already explains the authentication situation) instead of mislabeling a transport failure as lockfile tampering. Registry fetch errors no longer leak basic-auth credentials embedded in the registry URL (https://user:pass@host/) into their message.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.8.0: pnpm 11.8

Compare Source

Minor Changes
  • c112b61: Added a --dry-run option to pnpm install. It runs a full dependency resolution and reports what an install would change, but writes nothing to disk (no lockfile, no node_modules) and always exits with code 0. This mirrors the preview semantics of npm install --dry-run #​7340.

  • 179ebc4: pnpm run --no-bail now exits with a non-zero exit code when any of the executed scripts fail, while still running every matched script to completion. This makes the exit-code behavior of --no-bail consistent between recursive and non-recursive runs (recursive runs already failed at the end). Previously, a non-recursive pnpm run --no-bail always exited with code 0, even when a script failed #​8013.

  • 0474a9c: Added support for generating Node.js package maps at node_modules/.package-map.json during isolated and hoisted installs. Added the node-experimental-package-map setting to inject the generated map into pnpm-managed Node.js script environments, and the node-package-map-type setting to choose between standard and loose package maps.

  • dcededc: pnpm sbom now marks components reachable only through devDependencies with CycloneDX scope: "excluded" and the cdx:npm:package:development property. The excluded scope documents "component usage for test and other non-runtime purposes", which matches the semantics of a devDependency; the property is the CycloneDX npm-taxonomy marker emitted by @cyclonedx/cyclonedx-npm, so both modern (scope) and existing (property) consumers are covered. Components reachable at runtime (including installed optionalDependencies) omit scope and default to required.

  • 1495cb0: Added per-package SBOM generation with --out and --split flags. Use --out out/%s.cdx.json to write one SBOM per workspace package to individual files, or --split for NDJSON output to stdout. When --filter selects a single package, the SBOM root component now uses that package's metadata. Workspace inter-dependencies (workspace: protocol) and their transitive dependencies are included. Author, repository, and license fall back to the root manifest when the package doesn't define them.

  • 293921a: feat(view): support searching project manifest upward when package name is omitted

    When running pnpm view without a package name, the command now searches
    upward for the nearest project manifest (package.json, package.yaml, or package.json5) and uses its name field.
    If the manifest exists but lacks a name field, an error is thrown.

    This change also replaces the find-up dependency with empathic for
    improved performance and consistency across workspace tools.

Patch Changes
  • 29ab905: Fixed pnpm update overriding the version range policy of a named catalog whose name parses as a version (e.g. catalog:express4-21). The catalog: reference carries no pinning of its own, so the prefix from the catalog entry (such as ~) is now preserved instead of being widened to ^ #​10321.

  • bee4bf4: Security: validate config dependency names and versions from the env lockfile (pnpm-lock.yaml) before using them to build filesystem paths. A committed lockfile with a traversal-shaped configDependencies name (such as ../../PWNED) or version (such as ../../../PWNED) could previously cause pnpm install to create symlinks or write package files outside node_modules/.pnpm-config and the store. Names must now be valid npm package names and versions must be exact semver versions; the same validation is applied to optional subdependencies of config dependencies, and to the legacy workspace-manifest format before any lockfile is written. See GHSA-qrv3-253h-g69c.

  • 96bdd57: Fix link: workspace protocol switching to file: after pnpm rm is run from inside a workspace package whose target workspace dependency has its own dependencies, when injectWorkspacePackages: true is set. Follow-up to #​10575, which fixed the same symptom for workspace packages without dependencies.

  • 302a2f7: No longer warn about using both packageManager and devEngines.packageManager when the two fields pin the same package manager at the same version with the same integrity hash (e.g. both pnpm@11.5.1+sha512.…). Previously the hash was stripped from the legacy packageManager field but not from devEngines.packageManager, so even identical specifications looked like a mismatch #​12028.

    The warning still fires on any genuine divergence, and several cases now state the specific reason instead of a single generic message: a different package manager, a different version, or contradictory integrity hashes for the same version.

  • 3f0fb21: Fixed the progress line showing leftover characters from external processes that write to the terminal between progress updates (e.g. an SSH passphrase prompt would leave a fragment like added 0sa':). The interactive reporter now redraws each frame in place, erasing to the end of the display before reprinting, so any such remnants are cleared #​12350.

  • 564619f: Fixed pnpm approve-builds reporting "no packages awaiting approval" when a build-script dependency whose approval was revoked (e.g. after git stash drops the allowBuilds from pnpm-workspace.yaml) is re-added. The revoked packages are now correctly recorded in .modules.yaml so approve-builds can find them. #​12221

  • 3d1fd20: Skip the redundant "target bin directory already contains an exe called node" warning on Windows when the existing node.exe already matches the target (same hard link or identical content) pnpm/pnpm#12203.

  • 1b02b47: Fix macOS Gatekeeper blocking native binaries (.node, .dylib, .so) by removing the com.apple.quarantine extended attribute after importing them from the store.

    When pnpm imports files from its content-addressable store into node_modules, macOS preserves extended attributes, including com.apple.quarantine. If this xattr is present on a store blob (e.g. it was first written under a Gatekeeper-enabled app such as a Git client), it propagates to node_modules, and Gatekeeper blocks the native binary from loading even though pnpm already verified the file's integrity against the lockfile.

    After importing a package, pnpm now strips com.apple.quarantine from its native binaries, matching Homebrew's behaviour of dropping quarantine from verified downloads. The cleanup is macOS-only, runs in a single batched xattr call per package, is restricted to native binaries (other files are untouched), and is non-fatal (it logs a warning on unexpected errors).

    Fixes #​11056

  • 61969fb: Fix pnpm install with optimisticRepeatInstall incorrectly reporting Already up to date when pnpm-lock.yaml changed but project manifests did not. This affected workflows such as checking out or restoring only the lockfile #​12100.

    Also fixes checkDepsStatus to use the correct lockfile path when useGitBranchLockfile is enabled, so the optimistic fast-path and lockfile modification detection work with pnpm-lock.<branch>.yaml files instead of always stat'ing pnpm-lock.yaml. Merge-conflict detection now reads the resolved lockfile name as well, and with mergeGitBranchLockfiles enabled every pnpm-lock.*.yaml is scanned for modifications and conflicts. The git branch is now resolved by reading .git/HEAD directly (no process spawn) and uses the workspace directory rather than process.cwd().

  • 5c12968: Fix recursive updates of transitive dependencies when the update command mixes transitive dependency patterns with direct dependency selectors. For example, pnpm up -r "@babel/core" uuid now updates matching transitive @babel/core dependencies even when uuid is a direct dependency selector #​12103.

  • 9d79ba1: Register the pnpm update --no-save flag in the CLI help and option parser.

  • 0474a9c: Fixed pnpm import for Yarn v2 lockfiles when js-yaml v4 is installed.

  • 9e0c375: Fixed pnpm install repeatedly prompting to remove and reinstall node_modules in a workspace package when enableGlobalVirtualStore is enabled. The post-install build step recorded a per-project node_modules/.pnpm virtual store directory in node_modules/.modules.yaml, overwriting the global <storeDir>/links value the install step had written. The next install then detected a virtual-store mismatch (ERR_PNPM_UNEXPECTED_VIRTUAL_STORE). The build step now derives the same global virtual store directory as the install step #​12307.

  • 223d060: Document the --cpu, --os and --libc flags in the output of pnpm install --help. These flags were already supported but were only documented on the website #​12359.

  • e85aea2: Avoid reading README.md from disk when publishing if the publish manifest already provides a readme field. The README is now only read lazily, inside createExportableManifest, when it is actually needed.

  • 3188ae7: Fixed pnpm peers check to accept loose peer dependency ranges such as >=3.16.0 || >=4.0.0- when the installed peer version satisfies the range #​12149.

  • 531f2a3: Fixed pnpm update rewriting a workspace: dependency that points at a local path (e.g. workspace:../packages/foo/dist) into a normalized link: or version-range specifier. Such specifiers are now preserved verbatim when the workspace protocol is preserved #​3902.

  • fe66535: Fixed a lockfile non-convergence bug where an incremental install kept a duplicate transitive dependency that a fresh install would not produce. When a package is reused from the lockfile, its child edges are taken verbatim and bypass the preferred-versions walk, so a transitive dependency could stay pinned to an older version even after a direct dependency resolved to a higher version that satisfies the same range. The resolver now refreshes such a stale pin to the higher direct-dependency version during resolution — so the older version is never resolved or fetched, and the incremental result converges to the fresh one.

  • 6d35338: pnpm install detects changes inside local file dependencies again. The optimistic repeat-install fast path only tracks manifest and lockfile modification times, so edits inside a local dependency's directory (or a repacked local tarball) were reported as "Already up to date". Projects with local file dependencies (file: and bare local path or tarball specifiers, declared directly or through pnpm.overrides) now always run a full install, which refetches those dependencies, matching pnpm v10 behavior #​11795.

  • 4ca9247: Preserve the existing Node.js runtime version prefix when resolving node@runtime:<range> to a concrete version.

  • 30c7590: Create shorter CAFS temporary package directories to leave room for lifecycle scripts that create IPC socket paths under TMPDIR.

  • 13815ad: Reporter output (warnings, progress) for pnpm store and pnpm config subcommands now goes to stderr instead of stdout. This fixes scripts that capture their stdout (e.g. PNPM_STORE=$(pnpm store path), pnpm config list --json | jq) from getting warnings mixed into the result.

  • 1c05876: Avoid relinking unchanged child dependencies and remove stale child links during warm installs.

  • 817f99d: Fixed lockfile churn where a package's transitivePeerDependencies could be dropped (and shift between packages) when the package participates in a dependency cycle. A cycle re-entry resolves against truncated children, so it must not be cached as "pure"; otherwise sibling occurrences of the same package short-circuit and lose transitive peers depending on traversal order #​5108.

  • eba03e0: Fix pnpm install reporting "Already up to date" after a catalog entry in pnpm-workspace.yaml was reverted to a previous version. After an update modified a catalog, the workspace state cache stored the pre-update catalog versions, so reverting the entry back to its original version was not detected as an outdated state #​12418.

  • 3b54d79: pnpm update now keeps lockfile overrides that resolve through a catalog in sync with the catalog. Previously, when an override referenced a catalog (e.g. overrides: { foo: 'catalog:' }) and pnpm update bumped that catalog entry, the lockfile's catalogs advanced while the resolved overrides kept the old version. The resulting lockfile was internally inconsistent, so a later pnpm install --frozen-lockfile failed with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH.

  • 9d0a300: Fixed pnpm version --recursive so it honors the workspace selection. In recursive mode the version bump now applies to the packages resolved from the workspace filter (selectedProjectsGraph), matching the behavior of pnpm publish --recursive, instead of always bumping every workspace package #​11348.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.7.0: pnpm 11.7

Compare Source

Minor Changes
  • Added a new setting frozenStore (--frozen-store) that lets pnpm install run against a package store on a read-only filesystem (e.g. a Nix store, a read-only bind mount, an OCI layer). When enabled, pnpm opens the store's SQLite index.db through the immutable=1 URI — bypassing the WAL/-shm sidecar creation that otherwise fails on a read-only directory — and suppresses every store-write path (the index.db writer and the project-registry write). Pair it with --offline --frozen-lockfile against a fully-populated store. Under the global virtual store, package directories live inside the store, so if the store is missing the build output of a package whose lifecycle scripts are approved (or that has a patch), pnpm fails up front with ERR_PNPM_FROZEN_STORE_NEEDS_BUILD rather than crashing mid-build on a read-only write — seed the store with those builds first. Incompatible with --force and with a configured pnpr server, since both write into the store; the side-effects cache is likewise not written under frozenStore. If the store is missing its content directory, the install fails fast with ERR_PNPM_FROZEN_STORE_INCOMPLETE rather than attempting to initialize it. The read-only immutable=1 open requires Node.js >=22.15.0, >=23.11.0, or >=24.0.0; on older runtimes --frozen-store fails with a clear ERR_PNPM_FROZEN_STORE_UNSUPPORTED_NODE error. Bin-linking also tolerates a read-only store: under the global virtual store a package's bin source lives inside the store, so the chmod that makes it executable would be refused — with EPERM/EACCES, or with EROFS on a genuinely read-only filesystem. That chmod is redundant when the seed already ships its bins executable with a normalized shebang, so it is now skipped in that case, while a non-executable bin (or one still carrying a Windows CRLF shebang) on a read-only store still errors.

  • When pacquet (the Rust port of pnpm) is declared in configDependencies, pnpm now delegates dependency resolution to it too — not just materialization — provided the installed pacquet is new enough to support full resolving installs (>= 0.11.7).

    Previously pacquet only ran in frozen-install mode: pnpm always resolved the dependency graph itself (writing pnpm-lock.yaml) and handed pacquet a finished lockfile to fetch / import / link. With pacquet >= 0.11.7, a non-frozen pnpm install (default isolated nodeLinker, plain install) is delegated to pacquet end-to-end in a single pass — pacquet resolves the manifests, writes the lockfile, and materializes node_modules. pnpm detects the capability from the installed pacquet's version; older pacquet releases keep the resolve-then-materialize split, and add / update / remove still resolve in pnpm (it has to mutate the manifests first). This remains an opt-in preview of the Rust install engine #​11723.

  • Added a new opt-in --batch flag to pnpm publish --recursive that sends all selected packages to the registry in a single PUT /-/pnpm/v1/publish request instead of one request per package. The target registry has to implement the batch publish endpoint (pnpr does); registries that don't are reported with a clear ERR_PNPM_BATCH_PUBLISH_UNSUPPORTED error. The batch is processed all-or-nothing by pnpr: if any package in the batch fails validation, none of the packages are published.

Patch Changes
  • Reject path-traversal and reserved dependency aliases (such as ../../../escape, .bin, .pnpm, or node_modules) that come from a lockfile rather than a freshly resolved manifest. A crafted lockfile alias could otherwise be joined directly under a hoisted node_modules directory, letting package files be written outside the intended install root or overwrite pnpm-owned layout.

    The fix adds two layers:

    • The nodeLinker: hoisted graph builder now validates each alias at the directory sink (safeJoinModulesDir), matching the validation pnpm already performs when resolving aliases from manifests.
    • The lockfile verification gate (verifyLockfileResolutions) now runs an always-on, policy-independent check that rejects any importer or snapshot dependency alias that is not a valid package name, failing the install early — before any fetch or filesystem work — for every node linker at once.
  • Made shared package child resolution deterministic when the same package is reached through multiple contexts. pnpm now chooses the shallowest occurrence, then importer order, then parent path, instead of letting request timing decide the child context and missing-peer report pnpm/pnpm#12358.

  • Fix garbled summary line after submitting pnpm update -i and pnpm audit --fix -i. The interactive checkbox prompt previously printed every selected choice's full table row (label, current/target versions, workspace, URL) joined by commas, producing a wall of text after pressing Enter. The summary now lists only the selected package names (or vulnerability keys) by setting an explicit short per choice; the in-progress selection UI is unchanged.

  • Prevent pnpm patch-remove from removing files outside the configured patches directory.

  • Fixed pnpm publish ignoring strictSsl: false when publishing to registries with self-signed certificates. The strictSSL option is now forwarded to libnpmpublish / npm-registry-fetch so that strict-ssl=false in .npmrc or strictSsl: false in pnpm-workspace.yaml is respected during publish, the same way it is for pnpm install pnpm/pnpm#12012.

  • Fixed Cannot destructure property 'manifest' of 'manifestsByPath[rootDir]' as it is undefined regression introduced in 11.6.0 when running pnpm add <pkg> outside a workspace on Windows. selectProjectByDir was keying the resulting ProjectsGraph by opts.dir instead of project.rootDir, so downstream manifestsByPath lookups missed when the two paths normalized differently (typically drive-letter casing). pnpm/pnpm#12379

  • Git dependencies that point to a subdirectory of a repository (repo#commit&path:/sub/dir) keep their path in the lockfile again. Since the integrity of git-hosted tarballs started being pinned in the lockfile, any install that actually downloaded the tarball rebuilt the lockfile resolution as { integrity, tarball, gitHosted } and dropped the path field, while installs served from the store kept it — so the field disappeared seemingly at random. Without path, later installs from that lockfile silently unpacked the repository root instead of the subdirectory #​12304.

  • Fixed nondeterministic lockfile output that made pnpm dedupe --check fail intermittently in CI. When a locked peer provider was pinned for a dependency that has no child dependencies of its own, the pinned provider leaked into the shared parent scope, so siblings resolved after it could pick up an optional peer they should not see. Which siblings were affected depended on resolution order, which varies with network timing.

  • Sped up pnpm install with a frozen lockfile by running lockfile verification (the policy revalidation gate added for minimumReleaseAge/trustPolicy and the tarball-URL anti-tamper check) concurrently with fetching and linking instead of blocking the whole install on it. Dependency lifecycle scripts are still held back until verification succeeds, so no script runs on an unverified lockfile: if verification fails the install aborts before any dependency build, and if linking finishes first the install waits for the verification verdict before completing.

  • User-defined npm_config_* environment variables are now preserved during lifecycle script execution. Previously, all npm_-prefixed env vars were stripped, which caused user-set variables like npm_config_platform_arch to be lost pnpm/pnpm#12399.

  • pnpm can now use different auth tokens for different package scopes, even when those scopes use the same registry URL.

    Previously, auth was selected only by registry URL. If @org-a and @org-b both used https://npm.pkg.github.com/, they had to share the same token. This caused problems for registries that issue tokens per organization or per scope.

    Configure a scope-specific token by adding the package scope after the registry URL in the auth key:

    @org-a:registry=https://npm.pkg.github.com/
    @org-b:registry=https://npm.pkg.github.com/
    
    //npm.pkg.github.com/:@org-a:_authToken=${ORG_A_TOKEN}
    //npm.pkg.github.com/:@org-b:_authToken=${ORG_B_TOKEN}
    
    //npm.pkg.github.com/:_authToken=${FALLBACK_TOKEN}
    

    pnpm login --registry=https://npm.pkg.github.com --scope=@org-a writes the token to the same scope-specific auth key.

    When installing or publishing @org-a/*, pnpm uses ORG_A_TOKEN. For @org-b/*, pnpm uses ORG_B_TOKEN. Packages without a matching scope continue to use the registry-wide fallback token.

  • pnpm setup no longer prompts to approve build scripts for @pnpm/exe when installing the standalone executable. pnpm links the platform-specific binary itself, so the package's install scripts are skipped during the global self-install #​12377.

  • Close lockfile reads deterministically before rewriting lockfiles and keep pacquet's virtual store directory length aligned with pnpm on Windows.

  • A 304 Not Modified answer from the registry now renews the cached metadata file's mtime, so the minimumReleaseAge freshness shortcut keeps serving resolutions from the cache. Previously, once a cached packument grew older than minimumReleaseAge, every subsequent install re-validated it against the registry forever, because a 304 never rewrites the file.

  • Updated dependency ranges. Notably:

    • @pnpm/logger peer dependency range moved to ^1100.0.0.
    • msgpackr 1.11.8 → 2.0.4 (store index files remain byte-compatible in both directions).
    • open ^7.4.2 → ^11.0.0, memoize ^10 → ^11, cli-truncate ^5 → ^6, pidtree ^0.6 → ^1.
    • @yarnpkg/core 4.5.0 → 4.8.0, @rushstack/worker-pool 0.7.7 → 0.7.18, @cyclonedx/cyclonedx-library 10.0.0 → 10.1.0, @pnpm/config.nerf-dart ^1 → ^2, @pnpm/log.group 3.0.2 → 4.0.1, @pnpm/util.lex-comparator ^3 → ^4.
  • Updated @zkochan/cmd-shim to v9.0.6.

  • Fixed a Windows-only hang where a failed command could take 20–46 seconds to exit. On error, pnpm enumerates descendant processes (via pidtree) to terminate them, which on Windows shells out to wmic/PowerShell Get-CimInstance Win32_Process — a lookup that is extremely slow on some machines. The lookup is now bounded by a short timeout so it can no longer stall the process exit.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.6.0: pnpm 11.6

Compare 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 .npmrcregistry, @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 ~/.npmrc instead of the repo. In GitHub Actions, actions/setup-node with registry-url already writes a user-level .npmrc, so NODE_AUTH_TOKEN keeps working. For other CI where editing each pipeline is hard, set PNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc (or NPM_CONFIG_USERCONFIG=.npmrc) in the CI environment to declare the project .npmrc trusted.

See https://pnpm.io/npmrc for full migration details.

Minor Changes
  • pnpm install completes without re-resolving when pnpm-lock.yaml was deleted but node_modules is 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, restores pnpm-lock.yaml from 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_//… and pnpm_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 .npmrc but 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)) to min(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. The networkConcurrency setting still overrides the default.

Patch Changes
  • Improved the warning printed when a project .npmrc uses 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 ~/.npmrc or running pnpm config set "<key>" <value> — with a link to https://pnpm.io/npmrc. The pnpm config set example 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/libc fields 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 of supportedArchitectures. The missing platform fields of an optional dependency are now inferred from its name (e.g. @nx/nx-win32-arm64-msvcos: win32, cpu: arm64), so foreign-platform binaries are skipped without even downloading them #​11702.
Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.5.3: pnpm 11.5.3

Compare 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 .npmrcregistry, @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 ~/.npmrc instead of the repo. In GitHub Actions, actions/setup-node with registry-url already writes a user-level .npmrc, so NODE_AUTH_TOKEN keeps working. For other CI where editing each pipeline is hard, set PNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc (or NPM_CONFIG_USERCONFIG=.npmrc) in the CI environment to declare the project .npmrc trusted.

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 from pnpm-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 packageManagerDependencies to pnpm-lock.yaml when package manager policy is set to onFail: ignore or pmOnFail: ignore #​12228.

  • Avoid running dependency-status auto-install when the dependency status is unavailable without a project manifest.

  • Using the $ version reference syntax in overrides (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 the catalog: protocol instead.

  • Fixed pnpm config get globalconfig to return the global config.yaml path again pnpm/pnpm#11962.

  • Fixed bare --color so it does not consume the following CLI flag, allowing command shorthands like --parallel to expand correctly and forms like pnpm --color with current <command> to dispatch the inner command instead of failing with MISSING_WITH_CURRENT_CMD.

  • Fix pnpm install ignoring enableGlobalVirtualStore toggle 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) in configDependencies opts in to pnpm's Rust install engine. pnpm now verifies that the installed pacquet shim and the host's @pacquet/<platform>-<arch> binary carry a valid npm registry signature for their exact name@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 — the packageManager / devEngines.packageManager field makes pnpm download and run a specific pnpm version. pnpm now verifies the registry signature of pnpm, @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.

  • 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 --check alternate 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 bin names ("", ".", "..", 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 allowBuilds entries 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 the allowBuilds key. 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.txt before trusting its integrity hashes.

    When a repository requests a Node.js runtime (e.g. via devEngines.runtime / useNodeVersion), the download mirror is repository-configurable through node-mirror:<channel>. The integrity of the downloaded binary was only checked against SHASUMS256.txt fetched from that same mirror — a circular check that a malicious mirror could satisfy by serving a tampered binary together with a matching SHASUMS256.txt. pnpm then executes the binary (for example to run lifecycle scripts).

    pnpm now fetches SHASUMS256.txt.sig and 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 canonical nodejs/release-keys list.

    The musl variants from the hardcoded unofficial-builds.nodejs.org mirror are not repository-configurable and are signed by a different key, so they continue to be trusted over TLS.

Platinum Sponsors
Bit
OpenAI
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.5.2: pnpm 11.5.2

Compare 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 tarball URL points at the artifact the registry's own metadata lists for that name@version. Previously a tampered lockfile could pair a trusted name@version with 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 with ERR_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 with Invalid Version when the catalog entry for <pkg> is a version range (e.g. ^21.2.10) and catalogMode is strict or prefer. The catalog–version comparison now skips the equality check when either side is a range rather than passing a range to semver.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 multiple pnpm install processes 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 the package.json completion 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 rebuild pass (buildProjects). That pass resolved each package's location from the classic node_modules/.pnpm/<depPathToFilename> layout, which does not exist under the global virtual store — so native dependencies (e.g. packages using node-gyp / prebuild-install) were never built and failed to load at runtime (Cannot find module .../build/Release/*.node).

    buildProjects now resolves the global-virtual-store projection directory (<storeDir>/links/<hash>, computed with the same graph hash the installer uses) when enableGlobalVirtualStore is 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 from devEngines.runtime or pnpm runtime set) into a catalog when catalogMode is strict or prefer. A runtime: dependency round-trips to devEngines.runtime, which only recognizes the runtime: protocol; cataloging it rewrote the manifest entry to catalog:, which broke that round-trip, stranded it in devDependencies, and left devEngines.runtime untouched.

  • Skip lockfile minimumReleaseAge/trustPolicy verification for non-registry tarball protocols (for example file:), so local tarball dependencies are not incorrectly checked against npm registry metadata.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.5.1: pnpm 11.5.1

Compare Source

Patch Changes
  • Improve pnpm audit performance 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_agent for root lifecycle scripts during headless installs.
  • Preserve the integrity field of a remote (non-registry) tarball dependency when its lockfile entry is rebuilt. Re-resolving such a dependency without re-fetching it (for example via pnpm 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 with ERR_PNPM_MISSING_TARBALL_INTEGRITY #​12067.
  • Normalize a string repository field into the { type, url } object form when creating the publish manifest, matching npm's behavior. Some registries (e.g. Gitea/Codeberg) reject a string repository with a 500 Internal Server Error during pnpm 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-plugin peer-depends on both @typescript-eslint/parser and typescript, and @typescript-eslint/parser peer-depends on typescript), pnpm no longer reuses a hoisted instance of the shared peer that was resolved against a different version #​12079.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.5.0: pnpm 11.5

Compare Source

Minor Changes
  • Added a new hoistingLimits setting for nodeLinker: hoisted installs, mirroring yarn's nmHoistingLimits. It accepts none (the default — hoist as far as possible), workspaces (hoist only as far as each workspace package), or dependencies (hoist only up to each workspace package's direct dependencies). Originally proposed in #​6468, closing #​6457.

  • Replaced enquirer with @inquirer/prompts for all interactive prompts. Fixes the update -i scrolling 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 via usePagination
    • pnpm audit --fix -i: Same scrolling fix for vulnerability selection
    • pnpm approve-builds: Interactive build approval prompts updated
    • pnpm patch: Version selection and "apply to all" prompts updated
    • pnpm patch-remove: Patch removal selection updated
    • pnpm publish: Branch confirmation prompt updated
    • pnpm login: Credential prompts updated
    • pnpm run / pnpm exec (with verifyDepsBeforeRun=prompt): Confirmation prompt updated

    Vim-style j/k keys still work for up/down navigation in all interactive prompts.

    Internal: The OtpEnquirer and LoginEnquirer DI 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 approver field, 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 the findHit cache instead of running their own calculateDepPath are 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 add and pnpm dist-tag rm against npmjs.org failing without --otp with [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 sends npm-auth-type: web on dist-tag writes and surfaces the resulting OTP challenge through the existing browser-based 2FA flow (the same withOtpHandling helper used by pnpm 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 minimumReleaseAgeExclude handling in npm resolution fast paths so excluded packages do not get pinned to stale versions. Excludes are honored consistently during publishedBy metadata selection and cache-mtime shortcuts.

  • Fix the integrity field 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-lockfile installs fail with ERR_PNPM_MISSING_TARBALL_INTEGRITY. #​12001.

  • Skip dependency re-resolution when pnpm-lock.yaml is missing but node_modules/.pnpm/lock.yaml exists and still satisfies the manifest. pnpm install now reuses the materialized snapshot to regenerate pnpm-lock.yaml instead 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-lockfile still refuses to proceed when pnpm-lock.yaml is absent — the regenerated lockfile must be committed, so failing loudly is the correct behavior for CI.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.4.0: pnpm 11.4

Compare Source

Minor Changes
  • Treat tarball-integrity mismatches against the lockfile as a hard failure by default. Previously, pnpm install (non-frozen) would log ERR_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 install now exits with ERR_PNPM_TARBALL_INTEGRITY and 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.

    --force and pnpm update deliberately 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-lockfile behavior is unchanged. --fix-lockfile keeps its documented purpose (filling in missing lockfile entries) and is also not a bypass.

  • pnpm runtime set <name> <version> now saves the runtime to devEngines.runtime by default instead of engines.runtime. Pass --save-prod (or -P) to save it to engines.runtime instead #​11948.

Patch Changes
  • Fix a credential disclosure issue where an unscoped _authToken (or _auth, or username + _password, or tokenHelper) defined in one source — ~/.npmrc, ~/.config/pnpm/auth.ini, a workspace .npmrc, CLI flags, etc. — would be sent as an Authorization header 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 the registry= value declared in the same source (or the npmjs default registry if the source declares none). A later layer overriding registry= therefore cannot pull an unscoped credential along, because it is already pinned to the URL its author intended. ca/cafile are 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 the defaultRegistry parameter from createGetAuthHeaderByURI and getAuthHeadersFromCreds. Now that credentials are URL-scoped at load time, the merged configByUri never contains the empty-string "default registry" placeholder slot, so re-keying it onto the merged default registry is no longer needed.

  • Fix pnpm deploy crashing with ENOENT: ... lstat '<deployDir>/node_modules' when configDependencies declares pacquet (pacquet or @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 commit field is not a 40-character hexadecimal SHA before invoking git. A malicious lockfile could otherwise smuggle a value such as --upload-pack=<command> through git 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 EMFILE errors.

  • Reject patch files whose diff --git headers reference paths outside the patched package directory. Previously a malicious .patch file added via a pull request could write, delete, or rename arbitrary files reachable by the user running pnpm install.

  • Improve the log message that pnpm prints after auto-adding entries to minimumReleaseAgeExclude when minimumReleaseAge is set without minimumReleaseAgeStrict. The message previously referred to the internal "loose mode" terminology, which wasn't searchable in the docs; it now tells the user to set minimumReleaseAgeStrict to true if 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 into node_modules. A malicious registry package could otherwise use a transitive dependency key to make pnpm install create symlinks at attacker-chosen paths outside the intended node_modules directory.

  • Reject pnpm-lock.yaml entries whose remote tarball resolution: block is missing the integrity field. 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 strips integrity:) 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 with ERR_PNPM_MISSING_TARBALL_INTEGRITY. Git-hosted tarballs (gitHosted: true or a URL on codeload.github.com / bitbucket.org / gitlab.com) and file: tarballs are exempt — the commit SHA in a git-host URL and the user-controlled local path already anchor the bytes.

  • Validate devEngines.runtime and engines.runtime version ranges for node, deno, and bun when onFail is set to error or warn. Previously these settings only had an effect with onFail: 'download' — the error and warn modes silently did nothing #​11818. Violations now throw ERR_PNPM_BAD_RUNTIME_VERSION.

  • Require provenance before treating trusted publisher metadata as the strongest trust evidence.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.3.0: pnpm 11.3

Compare Source

See full v11.0.0 changelog
Migration guide: Migrating from v10 to v11

Minor Changes
  • Added pnpm stage with publish, list, view, approve, reject, and download subcommands for npm staged publishing.

  • Added a new setting trustLockfile. When true, pnpm install skips the supply-chain verification pass that re-applies minimumReleaseAge / 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 to false; verification stays on by default. Set in pnpm-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 (~4k lockfile entries with minimumReleaseAge + trustPolicy: no-downgrade enabled) 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-level modified field and the set of currently-listed version names. Fixes #​11860.

  • Implemented pnpm pkg command natively, following npm pkg standards.

  • Implemented pnpm repo command natively, following npm repo standards.

  • Implemented pnpm set-script (alias ss) natively. Adds or updates an entry in the scripts field of the project manifest, supporting package.json, package.json5, and package.yaml formats.

  • Add a skip-manifest-obfuscation option for pnpm pack and pnpm publish. When enabled, the original packageManager field and publish lifecycle scripts are kept in the packed/published manifest instead of being stripped. The pnpm-specific pnpm field continues to be omitted.

Patch Changes
  • Fixed pnpm dlx failing with ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND when the installed package's CAS slot is missing its package.json. Observed in the wild for pnpm dlx node@runtime:<version> when the GVS slot was populated without the synthesized manifest runtime archives need (they don't ship a package.json of 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, so dlx now falls back to the scopeless package name when the slot's manifest is unreadable — for single-bin packages (the dlx common case, including every runtime: spec) this matches what manifest.bin would have named. Multi-bin packages already require --package=<spec> <bin> to disambiguate and don't enter this code path.
  • Fixed non-determinism in pnpm dedupe and pnpm install when a dependency graph contains packages with transitive peer dependencies on each other (e.g. @aws-sdk/client-sts and @aws-sdk/client-sso-oidc) and auto-install-peers is enabled. The lockfile no longer flips between two equally-valid forms across consecutive runs. The root cause was that resolveDependencies pushed onto its pkgAddresses / postponedResolutionsQueue arrays from inside Promise.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 or pnpm/test-git-fetch#sha) was silently dropped from the manifest update and from pendingBuilds. The alias-keyed lookup added in that PR couldn't find a wantedDependency whose alias was undefined at parse time but resolved to a package name only after fetching, so the entry never made it into specsToUpsert. Restored the original index-based pairing between directDependencies and wantedDependencies; the catalog-protocol preservation that PR was originally fixing is unaffected because it's driven by rdd.catalogLookup.userSpecifiedBareSpecifier, not by the lookup. Fixes the three rebuilds dependencies / rebuilds specific dependencies / rebuild with pending option failures in building/commands/test/build/index.ts.
  • Fixed pnpm add --config leaving orphan entries in pnpm-lock.env.yaml (the optional subdependencies of the previously resolved version of the updated config dependency).
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.2.2: pnpm 11.2.2

Compare 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) to configDependencies in pnpm-workspace.yaml now delegates the materialization phase of pnpm install to 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 --config
    

    You'll see changes in pnpm-workspace.yaml and pnpm-lock.yaml that 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 to pnpm install (e.g. --no-runtime, --prod, --dev, --no-optional, --node-linker, --cpu/--os/--libc, --offline, --prefer-offline) are now forwarded to pacquet's install subcommand verbatim. Previously pacquet was invoked with a fixed argument list, so flags like --no-runtime were silently dropped. Flag forwarding is gated on the command being install/i; add, update, and dedupe still don't forward (their flag surface doesn't line up with pacquet's install).
  • Fixed pnpm up (and pnpm add / pnpm remove) failing with pacquet_package_manager::outdated_lockfile when pacquet is declared in configDependencies. pnpm now passes --ignore-manifest-check to pacquet so its --frozen-lockfile check doesn't fire against the (pre-mutation) package.json pnpm hasn't written yet #​11797. Requires a pacquet release that supports the flag — bump PACQUET_VERSION in the e2e tests once it ships.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.2.1: pnpm 11.2.1

Compare Source

Minor Changes
  • Experimental: Adding @pnpm/pacquet (the Rust port of pnpm) to configDependencies in pnpm-workspace.yaml now delegates the materialization phase of pnpm install to 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 --config
    

    You'll see changes in pnpm-workspace.yaml and pnpm-lock.yaml that 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: true in the env lockfile, matching how optional dependencies are recorded elsewhere in pnpm-lock.yaml. Previously, snapshots for the platform-specific subdeps pulled in via a config dep's optionalDependencies were 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 pickRegistryForPackage returning the wrong registry for an unscoped npm: alias under a scoped local name. A manifest entry like "@private/foo": "npm:lodash@^1" was routing the lodash fetch through registries["@private"], even though lodash is unscoped and doesn't live on that registry. The npm-alias branch now returns the alias target's own scope (or null for an unscoped target, falling through to registries.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.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.2.0: pnpm 11.2

Compare 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) to configDependencies in pnpm-workspace.yaml now delegates the materialization phase of pnpm install to 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 --config
    

    You'll see changes in pnpm-workspace.yaml and pnpm-lock.yaml that should be committed. If you experience any issues with pacquet, please let us know by mentioning this in the GitHub issue you create.

  • configDependencies now resolve and install one level of optionalDependencies declared by the config dependency, with os/cpu/libc platform filtering applied at install time. This unlocks the esbuild/swc-style pattern where a package ships platform-specific binaries via optionalDependencies — a config dependency can now do the same and have the matching binary symlinked next to it in the global virtual store, so require('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 optionalDependencies must 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. Previously pnpm login --scope foo errored with Unknown option: 'scope' despite the flag being listed in the online documentation #​11716.

  • pnpm outdated and pnpm update --interactive now 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 .npmrc being read from the wrong directory when pnpm is invoked from a different cwd (e.g. pnpm --dir <project> install from a CI wrapper or monorepo script). The path is now resolved against the directory of the .npmrc that declared it, not process.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.registry getting a trailing slash appended when registry is set in .npmrc and no registries.default is provided by pnpm-workspace.yaml. The sync from registries.default to config.registry introduced 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: true when the lockfile has been pruned (e.g. by turbo prune --docker):

    • Cannot use 'in' operator to search for 'directory' in undefined: a peer-dependency-variant injected snapshot inherits its resolution from the base packages: entry; when a pruner drops that base entry the readers crash. convertToLockfileObject now reconstructs the directory resolution from the file: depPath at load time — a single normalization point, so every reader sees a fully-formed snapshot.
    • ERR_PNPM_ENOENT on node_modules/.bin/<tool>: after prepare/postinstall, runLifecycleHooksConcurrently re-imported each injected workspace package; the scanDir-into-filesMap workaround fed target-internal paths to the importer, which the makeEmptyDir fast path (#​11088) then wiped. Drop the workaround and pass keepModulesDir: true so the importer preserves the target's existing node_modules (bin links + transitive deps) and source files keep their hardlinks.
  • Fixed pnpm login and pnpm logout ignoring registries.default from pnpm-workspace.yaml #​10099.

  • Fix the minimumReleaseAge (publishedBy) maturity shortcut to be inclusive at the cutoff. Previously, abbreviated metadata whose modified field equalled the cutoff fell off the fast path and triggered a full-metadata re-fetch (or a MISSING_TIME error when full metadata wasn't permitted). Since modified is an upper bound on every version's publish time, modified == publishedBy already implies every version passes the per-version <= filter in filterPkgMetadataByPublishDate, so the shortcut now accepts the boundary case directly. Strictly > (was >=) at the rejection branch.

  • Honor publishConfig.access when publishing packages.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.1.3: pnpm 11.1.3

Compare Source

Patch Changes
  • pnpm install now re-validates pnpm-lock.yaml entries against the active minimumReleaseAge and trustPolicy: '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 with ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION, ERR_PNPM_TRUST_DOWNGRADE, or the generic ERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATION when both policies trip in the same batch; minimumReleaseAgeExclude and trustPolicyExclude are 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 minimumReleaseAge keeps its built-in 24-hour value — auto-adds the immature picks to minimumReleaseAgeExclude in pnpm-workspace.yaml and 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 minimumReleaseAgeExclude and the install continues; declining aborts before the lockfile, package.json, or node_modules is touched.
    • Strict mode in CI (or any non-TTY context) aborts with ERR_PNPM_NO_MATURE_MATCHING_VERSION listing every offending entry, instead of failing on the first one the resolver hit.

    minimumReleaseAgeStrict auto-enables whenever the user explicitly sets minimumReleaseAge (CLI flag, env var, global config.yaml, or pnpm-workspace.yaml); set minimumReleaseAgeStrict: false to keep loose-mode auto-collect even with an explicit minimumReleaseAge value. Closes #​10438, #​10488, #​11687.

  • Allow redundant trailing base64 padding in .npmrc auth values and report invalid auth base64 with a pnpm error.

  • Make pnpm self-update respect minimumReleaseAge (and minimumReleaseAgeExclude) when resolving which pnpm version to install.

    When the latest dist-tag points to a version newer than the configured age threshold, self-update now selects the newest mature version instead unless excluded by minimumReleaseAgeExclude.

    Also makes dlx and outdated surface invalid minimumReleaseAgeExclude patterns under the same ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE error code already used by install, instead of leaking the internal ERR_PNPM_INVALID_VERSION_UNION / ERR_PNPM_NAME_PATTERN_IN_VERSION_UNION codes.

  • Global installs respect global config build policy (e.g., dangerouslyAllowAllBuilds from 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 by extractAndRemoveDependencyBuildOptions) were re-applied via globalDepsBuildConfig. This caused hasDependencyBuildOptions to return true (because {} is not null), blocking restoration of global config values like dangerouslyAllowAllBuilds. 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 globalDepsBuildConfig re-application, so that:

    1. Workspace manifest allowBuilds takes precedence (if present)
    2. Global config dangerouslyAllowAllBuilds is properly restored (if set and no workspace policy exists)
    3. Empty {} is only applied as a last resort when no policy is configured anywhere
  • Honor --silent when verifyDepsBeforeRun: install auto-installs dependencies before pnpm run or pnpm exec, preventing install output from being written to stdout #​11636.

  • Fix lockfile parsing failures when pnpm-lock.yaml contains 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.runtime pin when present, shell node otherwise — 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 from process.version — the Node that runs pnpm itself. That was wrong in two situations:

    1. @pnpm/exe SEA bundle. The bundle has its own embedded Node, not the node on the user's PATH that 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 shell node.
    2. engines.runtime / devEngines.runtime pin. When a project pins a Node version via devEngines.runtime (pnpm v11+), pnpm downloads that Node into node_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-version now exports engineName(nodeVersion?). Resolves the version in this order: explicit override → getSystemNodeVersion() (which already prefers node --version over process.version in SEA contexts) → process.version.
    • @pnpm/deps.graph-hasher now exports findRuntimeNodeVersion(snapshotKeys) — scans an iterable of lockfile snapshot keys for a node@runtime:<version> entry and returns its bare version string. calcDepState and calcGraphNodeHash/iterateHashedGraphNodes accept a nodeVersion? (in the options bag for the first, as a trailing parameter / ctx field for the others), forwarded to engineName(). The default (no override) preserves the pre-change behaviour. The legacy ENGINE_NAME constant in @pnpm/constants is 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 via findRuntimeNodeVersion(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-published pnpm package, and any other pnpm-compatible tool already produce.
    • Projects with a devEngines.runtime pin: 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.runtime into dependencies.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/linker already does on a per-package basis:

    • @pnpm/deps.graph-hasher adds readSnapshotRuntimePin(children) — reads the node entry from one snapshot's graph children and extracts the version from a node@runtime: value. Pairs with the existing findRuntimeNodeVersion(snapshotKeys) install-wide fallback (also now exported from @pnpm/deps.graph-hasher rather than @pnpm/engine.runtime.system-node-version, where it was a poor fit — system-node-version is about probing the host Node, not parsing lockfile-derived strings).
    • calcDepState and calcGraphNodeHash consult readSnapshotRuntimePin(graph[depPath].children) first and only fall back to the install-wide nodeVersion parameter when the snapshot doesn't pin its own Node.

    Pacquet mirrors the same precedence at the calc_graph_node_hash call site in package-manager/src/virtual_store_layout.rs — a new find_own_runtime_node_major(snapshot) helper reads each snapshot's dependencies for a node entry with Prefix::Runtime and overrides the install-wide engine when present.

    On upgrade, snapshots of dependencies that declare their own engines.runtime re-hash under that dep's pinned Node instead of the install-wide value. The old slots become prune-eligible. Closes #​11690.

  • Fixed pnpm publish failing with a 404 when authentication relied on OIDC trusted publishing alongside an .npmrc written by actions/setup-node (_authToken=${NODE_AUTH_TOKEN}) without NODE_AUTH_TOKEN being 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, without onFail) defaulting to onFail: "error" instead of the documented pmOnFail: "download". As a result, a project that pinned a different pnpm version via devEngines.packageManager and ran pnpm install from a mismatched pnpm version failed with a hard error, even though the migration table from managePackageManagerVersions: true to pmOnFail: download (default) promises the install would auto-download the wanted version #​11676.

    The array form of devEngines.packageManager keeps its existing per-element defaults (error for the last entry, ignore for the rest), since those reflect explicit prioritization by the user. Explicit onFail values continue to win.

  • Fix devEngines.packageManager not writing packageManagerDependencies to pnpm-lock.yaml when the lockfile lacks an env-doc entry. Previously the lockfile sync skipped resolution unless an existing packageManagerDependencies.pnpm entry needed refreshing, so a fresh install without onFail: "download" left the resolved pnpm version unrecorded — contradicting the documented behavior that the resolved version is stored in pnpm-lock.yaml #​11674.

  • Warn when package.json contains a legacy pnpm field with settings pnpm no longer reads from package.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.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.1.2: pnpm 11.1.2

Compare 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's fetch() 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 minimumReleaseAge handling for cached abbreviated metadata.

    The version-spec cache fast path no longer rethrows ERR_PNPM_MISSING_TIME under strictPublishedByCheck; 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 with fullMetadata: true if minimumReleaseAge is 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 -r not respecting named catalog groups. Previously, upgrading a dependency using a named catalog (e.g. "catalog:foo") would incorrectly rewrite package.json to "catalog:" and place the updated version in the default catalog instead of the named one #​10115.

  • Fixed optimisticRepeatInstall skipping pnpm-lock.yaml merge conflict resolution when the existing node_modules state appears up to date.

  • Fix minimumReleaseAge / resolutionMode: time-based installs failing on lockfiles whose time: block is missing entries. The npm-resolver's peek-from-store fast path now surfaces publishedAt from 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.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.1.1: pnpm 11.1.1

Compare 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 by verifyDepsBeforeRun). Previously the status check called findWorkspaceProjects, which validates each project's engines and os/cpu/libc and warns about useless fields in non-root manifests — work that the install pipeline already performs. With no nodeVersion threaded through, the engine check also fell back to the system Node from PATH and emitted spurious "Unsupported engine" warnings before scripts ran. Status-only callers now use findWorkspaceProjectsNoCheck; install paths continue to validate.
  • Fixed pnpm add <alias>:@scope/pkg for named registries. The local resolver was claiming any specifier containing / as a local directory, so pnpm add bit:@teambit/bit (with bit configured under namedRegistries) installed a bogus link to bit:@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-shim to 9.0.3. The sh shim it writes for .cmd / .bat targets now escapes the /C switch as //C, so it survives the path translation Git Bash applies when launching cmd.exe. Without this, a bare /C was rewritten to C:\ 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.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.1.0: pnpm 11.1

Compare Source

See full v11.0.0 changelog
Migration guide: Migrating from v10 to v11

Minor Changes
  • Added pnpm audit signatures to 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 .npmrc entries (e.g. //npm.pkg.github.com/:_authToken=...), so no separate auth mechanism is required.

    Additional aliases — or an override for the built-in gh alias, for GitHub Enterprise Server — can be configured under namedRegistries in pnpm-workspace.yaml:

    namedRegistries:
      gh: https://npm.pkg.github.example.com/
      work: https://npm.work.example.com/
    

    With this, work:@corp/lib@^2.0.0 resolves against https://npm.work.example.com/. #​11324.

  • Allow setting sbom spec version using --sbom-spec-version #​11389.

  • Add --no-runtime flag (config: runtime=false) to skip installing runtime entries (e.g. Node.js downloaded via devEngines.runtime) without modifying the lockfile. The lockfile keeps the runtime entry so frozen-lockfile validation still passes; only the runtime fetch and .bin linking are skipped. Useful in CI matrices where the runtime is provisioned externally (e.g. via pnpm runtime -g set node <version>) before pnpm install runs.

  • Added the pnpm bugs command that opens a package's bug tracker URL in the browser. With no arguments, it reads the current project's package.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>/issues when the bugs field is missing #​11279.

  • Added pnpm owner command to manage package owners on the registry.

Patch Changes
  • Added "published X ago by Y" information to the pnpm view command output, similar to npm view. This is useful when comparing against minimumReleaseAge.

    For example, pnpm view pnpm now shows:

    published 17 hours ago by GitHub Actions
    
  • pnpm publish now honors the configured HTTP/HTTPS proxy (including https_proxy/http_proxy/no_proxy environment variables) when polling the registry's doneUrl during the web-based authentication flow. Previously the poll bypassed the proxy, causing the registry to respond 403 from a different source IP and the login to never complete #​11561.

  • pnpm add -g now 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 bar installs foo and bar as two independent globals — removing one does not affect the other.
    • pnpm add -g foo,bar qar bundles foo and bar into a single isolated install while qar is installed on its own.

    Related: #​11587.

  • pnpm runtime set <name> <version> no longer fails in the root of a multi-package workspace with the ADDING_TO_ROOT error. Installing the workspace root is a valid target for a runtime, so the command now bypasses that safety check.

  • Fix pnpm --version hanging for the lifetime of the worker pool after the version was printed. main.ts's --version short-circuit returned before reaching the command-handler finally that calls finishWorkers(), so the worker pool that switchCliVersion had spawned during integrity resolution stayed alive and held the Node event loop open. The CLI entry now runs finishWorkers() from its own finally, so every exit path tears the pool down.

    Repro: pnpm --version in a workspace whose devEngines.packageManager version already matches the running pnpm + onFail: "download". switchCliVersion resolves the integrity (spawning workers), finds nothing to swap, returns. The version prints, then the process hangs.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.9: pnpm 11.0.9

Compare 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.gz instead of the GitLab API endpoint that contained an encoded slash (%2F) between user and project. The encoded slash both triggered 406 Not Acceptable responses from GitLab and produced virtual store directory names that Node refused to import (ERR_INVALID_MODULE_SPECIFIER) #​11533.
  • Honor NPM_CONFIG_USERCONFIG (and its lowercase npm_config_userconfig form) 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 notably actions/setup-node, which writes registry credentials to ${runner.temp}/.npmrc and exports NPM_CONFIG_USERCONFIG to reference it. Without this, GitHub Actions workflows using actions/setup-node to authenticate to private registries broke after upgrading to pnpm v11. PNPM-prefixed env vars and npmrcAuthFile from the global config.yaml continue to take precedence #​11539.
  • Fix pnpm pack not bundling dependencies listed in bundleDependencies (or bundledDependencies). 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 — bundleDependencies were silently dropped from the tarball #​11519.
  • Fixed the pnpm CLI crashing with a confusing SyntaxError: Invalid regular expression flags instead of printing a clear "requires Node.js v22.13" error when launched on an unsupported Node.js version. The Node.js version check in bin/pnpm.mjs was effectively dead code because the static import of the bundled dist/pnpm.mjs was hoisted by the ES module loader and parsed before the check could run #​11546.
  • Fixed pnpm --prefix=<dir> install overwriting the existing pnpm-workspace.yaml in <dir> with set this to true or false placeholders. The renamed --prefix option (which maps to dir) was not honored when locating the workspace root, so the workspace manifest's allowBuilds settings were not loaded into config and got clobbered when ignored builds were auto-populated #​11535.
  • Fixed pnpm publish --provenance failing 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.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.8: pnpm 11.0.8

Compare 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.yaml when they cannot be derived from name+version+registry, even with the default lockfileIncludeTarballUrl: false. Without this, pnpm install --frozen-lockfile from an empty store fails with ERR_PNPM_FETCH_404 for 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: true continues to force the URL into the lockfile for every package #​11276.
  • Run preversion, version, and postversion lifecycle scripts for pnpm version.
  • Fixed ERR_PNPM_BAD_TARBALL_SIZE when a registry serves tarballs with an end-to-end Content-Encoding (e.g. gzip). Tarballs are already compressed, so the fetcher now requests them with Accept-Encoding: identity (matching pnpm v10's effective behavior) and, as defense in depth against misbehaving servers, no longer enforces the strict Content-Length check when the response declares a Content-EncodingContent-Length in that case refers to the encoded payload, not the decoded bytes the fetch implementation yields #​11506.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.7: pnpm 11.0.7

Compare Source

Patch Changes
  • Restore the execute bit on the node-gyp shims packed inside @pnpm/exe (dist/node-gyp-bin/node-gyp, dist/node-gyp-bin/node-gyp.cmd, and dist/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 invoked node-gyp rebuild with sh: 1: node-gyp: Permission denied #​11483.

  • Fixed the pn, pnpx, and pnx aliases failing in Git Bash / MSYS2 on Windows when pnpm was installed via @pnpm/exe (or after pnpm self-update) #​11486. Running pnpx (or pnx) printed the cmd.exe banner and dropped the user into an interactive command prompt instead of running pnpm dlx. The bin field rewrite on Windows was pointing those aliases at .cmd files; cmd-shim's Bash shim for a .cmd target wraps it in exec cmd /C ..., and MSYS2 mangles /C into a Windows path before cmd.exe sees it. The aliases are now .exe hardlinks of the SEA binary, which detects which name it was launched as via process.execPath and prepends dlx for pnpx / pnx.

  • Fix pnpm install recreating node_modules after pnpm fetch. pnpm fetch records empty hoistPattern and publicHoistPattern in .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 with virtualStoreOnly: true so 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: true field 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 via pnpm config set --location global) instead of being restricted to pnpm-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 _authToken in pnpm 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_TOKEN env 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's CIRCLE_OIDC_TOKEN_V2, Buildkite, etc.) can forward its token via NPM_ID_TOKEN and 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 --help or --version. Previously the CLI argument parser short-circuited those flags before universal options were preserved, so pnpm audit --pm-on-fail=ignore --help and pnpm --pm-on-fail=ignore --version reported the strict packageManager mismatch instead of running the requested action #​11487.

  • Fix a regression where pnpm --recursive --filter '!<pkg>' run/exec/test/add would include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative --filter arguments are provided, matching the documented behavior. To include the root, pass --include-workspace-root #​11341.

  • Restore npm-CLI-compatible --json stdout output for pnpm 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 notably nx 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 }, mirroring npm publish --json.
    • pnpm publish -r --json → array of those objects, mirroring pnpm pack --json's shape choice.
    • pnpm publish -r --report-summary → existing pnpm-publish-summary.json envelope { publishedPackages: [...] } is preserved, but each entry is upgraded to the same per-package shape (additive — name and version are still present).
  • pnpm config get @<scope>:registry now reports the same URL that pnpm publish and the resolvers actually use. Previously, config get only consulted .npmrc, while publish/install used the merged map that includes pnpm-workspace.yaml's registries block — so the two could diverge silently and a publish could go to the wrong registry #​11492.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.6: pnpm 11.0.6

Compare Source

Patch Changes
  • Fix pnpm_config_npmrc_auth_file and pnpm_config_userconfig env vars not actually loading the custom .npmrc. The env vars were parsed and assigned to the resolved config, but only after loadNpmrcConfig had 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 .npmrc is loaded #​11465.
  • Preserve the original key order in pnpm-workspace.yaml when updating it. Existing keys keep their position, and new keys are inserted in alphabetical position when the existing keys are already sorted (with a leading packages key allowed) or appended at the end otherwise.
  • Fixed pnpm self-update on installations originally set up by pnpm v10. v10 added PNPM_HOME directly to PATH and wrote a pnpm bootstrap shim there. v11 setup writes shims under PNPM_HOME/bin instead, so when a v10 user upgrades to v11 the legacy shim at PNPM_HOME keeps pointing into the old .tools/<version> install — pnpm --version continues to report the pre-update version even though the new version was installed under global/v11. Self-update now detects this layout, refreshes the legacy shims so the upgrade actually takes effect, and prints a hint suggesting pnpm setup to 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 in config.yaml and 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-level pnpm-workspace.yaml, or sharing them across projects via config dependencies.
  • Throw a pnpm error when overrides has an invalid shape or contains a non-string value.
  • Validate all readPackage dependency map fields, including devDependencies, and reject falsy non-object invalid values instead of silently accepting them.
  • Prevent crashes during pnpm config, pnpm set, and pnpm get by tolerating configDependencies install failures. For these commands, a failure to install configDependencies (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 allowBuilds as 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 the pnpm dlx / pnpx command, resulting in a catalog entry not found error.
  • Accept PNPM_CONFIG_* (uppercase) environment variables in addition to pnpm_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.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.5: pnpm 11.0.5

Compare Source

Patch Changes
  • Drop the darwin-x64 artifact from @pnpm/exe and from the GitHub release page. The Node.js SEA mechanism pnpm pack-app uses 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 with codesign or ldid doesn'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 (and pnpx/pnx/pnpm create) now runs the same interactive approve-builds prompt as pnpm add -g when the package being launched depends on transitive packages with install scripts. Previously, the v11 strictDepBuilds default made dlx fail with ERR_PNPM_IGNORED_BUILDS and 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 --json and pnpm -g ls --parseable so 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 like npm-check-updates that 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 regular list flow is used and the full dependency tree is shown.

  • Fixed pnpm publish to honor publishConfig.registry from package.json when publishing a single package. The native publish flow introduced in v11 was reading the registry from .npmrc only, ignoring the per-package override #​11419.

  • When strictPeerDependencies is true, the ERR_PNPM_PEER_DEP_ISSUES error once again renders the peer dependency issues inline using the same format as pnpm peers check, so users (and CI tools like Renovate) can see what failed without running pnpm peers check separately #​11439.

  • The WARN and 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. when NO_COLOR is 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.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.4: pnpm 11.0.4

Compare Source

Patch Changes
  • Fixed pnpm ci not reinstalling workspace package node_modules directories after the clean step #​11427.
  • Remove pnpm's workspace state file when cleaning node_modules so pnpm ci performs a fresh install after the clean step.
  • Do not remove pnpm-lock.yaml during pnpm clean when lockfile: true is configured in pnpm-workspace.yaml. The lockfile is only removed when the --lockfile option is passed to pnpm clean.
  • pnpm self-update (with no version argument) no longer downgrades pnpm when the registry's latest dist-tag points to an older release than the currently active version. Run pnpm self-update latest to force a downgrade #​11418.
  • minimumReleaseAgeStrict now defaults to true whenever the user explicitly sets minimumReleaseAge (via pnpm-workspace.yaml, the global config.yaml, the CLI, or pnpm_config_* env vars).
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.3: pnpm 11.0.3

Compare 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_404 when installing a project whose lockfile depends on a file: tarball. The previous behavior dropped the tarball field from file: and git-hosted resolutions when lockfile-include-tarball-url=false (the default), even though those URLs cannot be reconstructed from the package name, version, and registry #​11407.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.2: pnpm 11.0.2

Compare Source

Patch Changes
  • Fix ENOENT symlink failure when pnpm add -g triggers the approve-builds prompt. The global add flow used to forward an absolute modulesDir (<installDir>/node_modules) into the install run by approve-builds. The install layer treated modulesDir as a path relative to lockfileDir and joined it again, producing a doubled path on Windows because path.join does not collapse an embedded absolute path. The hoist step then tried to mkdir and symlink under <installDir>\<installDir>\node_modules\.pnpm\node_modules\... and failed with ENOENT #​11403.
  • Fixed packageManagerDependencies going stale when pnpm is invoked through corepack. The lockfile sync (and the devEngines.packageManager version 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.directory when packages publish from a generated directory #​11239.
  • Fix negated os / cpu entries (e.g. ["!win32"]) being incorrectly rejected when supportedArchitectures expands to multiple platforms #​11375.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.1: pnpm 11.0.1

Compare Source

Patch Changes
  • Report unknown top-level options before falling back to implicit pnpm run scripts.
  • Reject null named catalogs in workspace manifests with InvalidWorkspaceManifestError instead of crashing with a raw TypeError.
  • Populate download location for git-sourced dependencies in SBOM output. Previously pnpm sbom emitted NOASSERTION (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-update now keeps package.json's packageManager and devEngines.packageManager in sync. When the legacy packageManager field pins pnpm, both fields are rewritten to the new exact pnpm version on update — packageManager to pnpm@<version> (without an integrity hash), and devEngines.packageManager.version to the same exact <version> (dropping any range operator). When only devEngines.packageManager is declared, the existing range-preserving behavior is unchanged #​11388.
  • Sort the keys of the overrides object returned by pnpm audit --fix so that the log output order matches the order written to pnpm-workspace.yaml.
  • Update the env lockfile's packageManagerDependencies entry when devEngines.packageManager declares 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.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.0.0: pnpm 11

Compare 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 defaultminimumReleaseAge defaults to 1 day (newly published packages are not resolved for 24h) and blockExoticSubdeps defaults to true.
  • allowBuilds replaces the old build-dependency settingsonlyBuiltDependencies, onlyBuiltDependenciesFile, neverBuiltDependencies, ignoredBuiltDependencies, and ignoreDepScripts have been removed.
  • Global installs are isolated and use the global virtual store by default — each pnpm add -g gets its own directory with its own package.json, node_modules, and lockfile.
  • New SQLite-backed store index (store v11) with bundled manifests and hex digests, reducing filesystem syscalls and speeding up installation.
  • Native publish flowpnpm publish, login, logout, view, deprecate, unpublish, dist-tag, and version no longer delegate to the npm CLI, and the remaining npm passthrough commands now throw "not implemented".
  • pnpm audit uses npm's bulk advisories endpoint — the legacy /security/audits endpoints are gone. CVE-based filtering has been replaced with GHSA-based filtering: migrate auditConfig.ignoreCves entries to auditConfig.ignoreGhsas.
  • .npmrc is auth/registry only — all other settings must live in pnpm-workspace.yaml or the new global config.yaml, and environment variables use the pnpm_config_* prefix.
  • Runtime installs are slimmer — installing a Node.js runtime via node@runtime:<version> no longer extracts the bundled npm, npx, and corepack, roughly halving the files pnpm has to hash, write, and link.
Minor
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: optimisticRepeatInstall is now true, verifyDepsBeforeRun is now install, minimumReleaseAge is now 1440 (1 day), and minimumReleaseAgeStrict is false. 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, set minimumReleaseAge: 0 in pnpm-workspace.yaml #​11158.

  • strictDepBuilds is true by default.

  • blockExoticSubdeps is true by default.

  • Removed deprecated build dependency settings: onlyBuiltDependencies, onlyBuiltDependenciesFile, neverBuiltDependencies, ignoredBuiltDependencies, and ignoreDepScripts #​11220.

    Use the allowBuilds setting instead. It is a map where keys are package name patterns and values are booleans:

    • true means the package is allowed to run build scripts
    • false means 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:
      - esbuild
    

    After:

    allowBuilds:
      electron: true
      core-js: false
      esbuild: false
    
  • Removed allowNonAppliedPatches in favor of allowUnusedPatches.

  • 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.json from 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.db with 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) and pnx now use the global virtual store by default. Packages are stored at {storeDir}/links instead of per-project .pnpm directories. This can be disabled by setting enableGlobalVirtualStore: 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 package
    • pnpm update -g [pkg] re-installs packages in new isolated directories
    • pnpm list -g scans isolated directories to show all installed global packages
    • pnpm install -g (no args) is no longer supported; use pnpm add -g <pkg> instead
  • Globally installed binaries are now stored in a bin subdirectory of PNPM_HOME instead of directly in PNPM_HOME. This prevents internal directories like global/ and store/ from polluting shell autocompletion when PNPM_HOME is on PATH #​10986. After upgrading, run pnpm setup to 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, use pnpm link ./foo instead of pnpm link foo.
    • pnpm link --global is removed. Use pnpm add -g . to register a local package's bins globally.
    • pnpm link (no arguments) is removed. Use pnpm link <dir> with an explicit path instead.
Configuration
  • pnpm no longer reads all settings from .npmrc. Only auth and registry settings are read from .npmrc files. All other settings (like hoistPattern, nodeLinker, shamefullyHoist, etc.) must be configured in pnpm-workspace.yaml or the global ~/.config/pnpm/config.yaml #​11189.

  • Network settings (httpProxy, httpsProxy, noProxy, localAddress, strictSsl, gitShallowHosts) are now written to config.yaml (global) or pnpm-workspace.yaml (local) instead of .npmrc/auth.ini. They are still readable from .npmrc for easier migration from the npm CLI #​11209.

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

    pnpm no longer reads the npm global config at $PREFIX/etc/npmrc.

    pnpm login writes auth tokens to ~/.config/pnpm/auth.ini.

    New registries setting in pnpm-workspace.yaml:

    registries:
      default: https://registry.npmjs.org/
      "@my-org": https://private.example.com/
      "@internal": https://nexus.corp.com/
    

    Auth tokens in ~/.npmrc still work — pnpm continues to read ~/.npmrc as a fallback for registry authentication. The new npmrcAuthFile setting can be used to point to a different file instead of ~/.npmrc.

  • Replace workspace project specific .npmrc with packageConfigs in pnpm-workspace.yaml.

    A workspace manifest with packageConfigs looks 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 pnpm field of package.json. Settings should be defined in pnpm-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 --json still prints all types of values as JSON, as before.

  • pnpm config get <array> now prints a JSON array.

  • pnpm config list now prints a JSON object instead of INI formatted text.

  • pnpm config list and pnpm config get (without argument) now hide auth-related settings.

  • pnpm config list and pnpm 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 get and pnpm config list no 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, and version — have been reimplemented natively in pnpm (see New Commands below).

  • pnpm publish now works without the npm CLI.

    The One-time Password feature now reads from PNPM_CONFIG_OTP instead of NPM_CONFIG_OTP:

    export PNPM_CONFIG_OTP='<your OTP here>'
    pnpm publish --no-git-checks
    

    If the registry requests OTP and the user has not provided it via the PNPM_CONFIG_OTP environment variable or the --otp flag, 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 publish no longer calls npm 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 use pnpm pack && npm publish *.tgz as a workaround.

  • Removed the pnpm server command #​10463.

  • Removed support for the useNodeVersion and executionEnv.nodeVersion fields. devEngines.runtime and engines.runtime should be used instead #​10373.

  • Removed support for hooks.fetchers. We now have a new API for custom fetchers and resolvers via the fetchers field of pnpmfile.

Lifecycle Scripts
  • pnpm no longer populates npm_config_* environment variables from the pnpm config during lifecycle scripts. Only well-known npm_* env vars are now set, matching Yarn's behavior #​11116.
CLI Output
  • Cleaner output for script execution: pnpm now prints $ command instead of > pkg@version stage path\n> command, and shows project name and path only when running in a different directory. The $ command line 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 check to view the issues #​11133.
Lockfile
  • Simplified patchedDependencies lockfile format from Record<string, { path: string, hash: string }> to Record<string, string> (selector to hash). Existing lockfiles with the old format are automatically migrated #​10911.
Other
  • The default value of the type field in the package.json file of the project initialized by pnpm init command has been changed to module.

  • Added support for lowercase options in pnpm add: -d, -p, -o, -e #​9197.

    When using the pnpm add command only:

    • -p is now an alias for --save-prod instead of --parseable
    • -d is now an alias for --save-dev instead of --loglevel=info
  • The root workspace project is no longer excluded when it is explicitly selected via a filter #​10465.

Audit
  • pnpm audit now calls npm's /-/npm/v1/security/advisories/bulk endpoint. 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.ignoreCvesauditConfig.ignoreGhsas (the previous key is no longer recognized)
    • pnpm audit --ignore <id> / pnpm audit --ignore-unfixable now 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-NNNNN entry in your auditConfig.ignoreCves with the corresponding GHSA-xxxx-xxxx-xxxx value (visible in the More info column of pnpm audit output) and move it under auditConfig.ignoreGhsas.

Package Manager Settings
  • Breaking: removed the managePackageManagerVersions, packageManagerStrict, and packageManagerStrictVersion settings. They existed only to derive the onFail behavior for the legacy packageManager field, and the pmOnFail setting introduced alongside pnpm with subsumes all three — it directly sets the onFail behavior of both packageManager and devEngines.packageManager. The COREPACK_ENABLE_STRICT environment variable is no longer honored (it only gated packageManagerStrict); use pmOnFail instead.

    Migration:

    Removed setting Replace with
    managePackageManagerVersions: true pmOnFail: download (default)
    managePackageManagerVersions: false pmOnFail: ignore
    packageManagerStrict: false pmOnFail: warn
    packageManagerStrictVersion: true pmOnFail: error
    COREPACK_ENABLE_STRICT=0 pmOnFail: warn
Runtime Installs
  • Installing a Node.js runtime via node@runtime:<version> (including pnpm env use and pnpm runtime set node) no longer extracts the bundled npm, npx, and corepack from the Node.js archive. 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 need npm can 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 (and pnpm adduser alias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login #​11094.
  • Added pnpm logout command 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 deprecate and pnpm undeprecate commands for setting and removing deprecation messages on package versions without delegating to the npm CLI #​11120.
  • Added native pnpm unpublish command. Supports unpublishing specific versions, version ranges via semver, and entire packages with --force #​11128.
  • Added native pnpm dist-tag command (ls, add, rm subcommands) #​11218.
  • Added pnpm sbom command for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats #​9088.
  • Added pnpm clean command that safely removes node_modules directories from all workspace projects #​10707. Use --lockfile to also remove pnpm-lock.yaml files.
  • Added a new command pnpm runtime set <runtime name> <runtime version spec> [-g] for installing runtimes. Deprecated pnpm env use in 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 ci command for clean installs #​6100. The command runs pnpm clean followed by pnpm 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 check command that checks for unmet and missing peer dependency issues by reading the lockfile #​7087.
  • Implemented the version command natively in pnpm to support workspaces and workspace: protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration #​10879.
  • pnpm audit --fix now supports a new interactive mode via --interactive/-i.
  • Added the pnpm docs command and its alias pnpm home. This command opens the package documentation or homepage in the browser. When the package has no valid homepage, it falls back to https://npmx.dev/package/<name>.
  • Added native pnpm ping command to test registry connectivity. Provides a simple way to verify connectivity to the configured registry without requiring external tools.
  • Implemented native search command and its aliases (s, se, find).
  • Implemented native star, unstar, stars, and whoami commands.
  • 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's packageManager and devEngines.packageManager pins.
  • Added a new pnpm pack-app command 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 rc file and local .npmrc.
    • pnpm-specific settings, which can only be loaded from YAML files such as the global config.yaml and local pnpm-workspace.yaml.
  • Added support for loading environment variables whose names start with pnpm_config_ into config. These environment variables override settings from pnpm-workspace.yaml but not CLI arguments.

  • Added support for reading allowBuilds from pnpm-workspace.yaml in the global package directory for global installs.

  • Added support for pnpm config get globalconfig to retrieve the global config file path #​9977.

  • Added a new setting virtualStoreOnly that 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 fetch now uses this mode internally #​10840.

  • Added support for specifying the pnpm version via devEngines.packageManager in package.json. Unlike the packageManager field, this supports version ranges. The resolved version is stored in pnpm-lock.yaml and reused if it still satisfies the range #​10932.

  • Added a new dedupePeers setting 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 (foo@1.0.0(bar@2.0.0)). 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 into node_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 in pnpm-lock.yaml instead of inlined in pnpm-workspace.yaml: the workspace manifest contains only clean version specifiers for configDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also stores packageManagerDependencies resolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #​10912 #​10964.

  • Added nodeDownloadMirrors setting to configure custom Node.js download mirrors in pnpm-workspace.yaml. This replaces the node-mirror:<channel> .npmrc setting, which is no longer read #​11194:

    nodeDownloadMirrors:
      release: https://my-mirror.example.com/download/release/
    
  • pnpm dlx and pnpm create now respect security and trust policy settings (minimumReleaseAge, minimumReleaseAgeExclude, minimumReleaseAgeStrict, trustPolicy, trustPolicyExclude, trustPolicyIgnoreAfter) from project-level configuration #​11183.

  • pnpm init now writes a devEngines.packageManager field instead of the packageManager field when init-package-manager is enabled.

  • Added a new setting runtimeOnFail that overrides the onFail field of devEngines.runtime (and engines.runtime) in the root project's package.json. Accepted values: ignore, warn, error, download. For example, setting runtimeOnFail=download makes pnpm download the declared runtime version even when the manifest does not set onFail: "download".

  • Added a new setting minimumReleaseAgeIgnoreMissingTime, which is true by default. When enabled, pnpm skips the minimumReleaseAge maturity check if the registry metadata does not include the time field. Set to false to 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 .mjs extension. When .pnpmfile.mjs exists, it takes priority over .pnpmfile.cjs and only one is loaded #​9730.
CLI & Other
  • The built-in clean, setup, deploy, and rebuild commands now prefer user scripts over built-in commands. When a project's package.json has a script with the same name, pnpm executes the script instead of the built-in command. Added purge as an alias for the built-in clean command, which always runs the built-in regardless of scripts #​11118.
  • Added -F as a short alias for the --filter option.
  • Added support for hidden scripts. Scripts starting with . are hidden and cannot be run directly via pnpm run. They can only be called from other scripts. Hidden scripts are also omitted from the pnpm run listing #​11041.
  • pnpm approve-builds now 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 allowBuilds are automatically added to pnpm-workspace.yaml with a placeholder value, so users can manually set them to true or false #​11030.
  • Added pn and pnx short aliases for pnpm and pnpx (pnpm dlx) #​11052.
  • pnpm store prune now displays the total size of removed files #​11047.
  • pnpm audit --fix now adds the minimum patched version for each advisory to minimumReleaseAgeExclude in pnpm-workspace.yaml, so the security fix can be installed without waiting for minimumReleaseAge #​11216.
  • pnpm now warns when optimisticRepeatInstall skips shouldRefreshResolution hooks #​10995.
Performance
  • Replaced node-fetch with native undici for 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 gunzipSync chunk 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-Since for 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.write instead of console.error for script logging #​11140.

  • Respected the frozen-lockfile flag when migrating config dependencies #​11067.

  • Removed the --workspace flag from the version command #​11115.

  • Handled ENOTSUP error in the clone import path during parallel I/O #​11117.

  • Fixed pnpm audit command.

  • 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 rc config file to npm.

  • Fixed YAML formatting preservation in pnpm-workspace.yaml when running commands like pnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.

    Closes #​10425

  • The parameter set by the --allow-build flag is now written to allowBuilds.

  • Fixed a bug in which specifying filter in pnpm-workspace.yaml would 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 strictDepBuilds and allowBuilds checks being bypassed when a package's build side-effects are cached in the store #​11039.

  • In GVS mode, pnpm approve-builds now runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changing allowBuilds #​11043.

  • Fixed a crash in the lockfile merger when merging non-semver version strings (e.g. link:, file:, git URLs) #​11102.

  • Handled ENOTSUP error in linkOrCopy during 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 _password handling 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 cleanupUnusedCatalogs when they are referenced only from workspace overrides #​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 Bearer to the authorization token generated by tokenHelper if it is missing, aligning with npm's behavior #​11097.

  • Propagated error cause when throwing PnpmError in @pnpm/npm-resolver #​10990.

  • Fixed SQLite race condition during store initialization on Windows.

  • Removed rimrafSync in importIndexedDir fast-path error handler #​11168.

  • Fixed pnpm dedupe --check unexpectedly failing due to non-deterministic resolution #​11110.

  • Fixed empty files not being rejected in isEmptyDirOrNothing #​11182.

  • Fixed .bat/.cmd token helpers not working on Windows due to missing shell: true option.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.34.5: pnpm 10.34.5

Compare Source

Patch Changes
  • 78e29fe: Prevent a crafted pnpm-lock.yaml from writing package content outside the virtual store. A dependency path key whose name reconstructs to a path-traversal sequence (e.g. ../../../tmp/x@1.0.0) is now rejected by the isolated (virtual-store) linker and the Plug'n'Play resolver map, matching the containment already applied to the hoisted linker. Under the global virtual store, a traversal in the version-derived path segment (e.g. a snapshot version: "../../x") is now rejected at iterateHashedGraphNodes, the single point every global-virtual-store slot path funnels through.
  • 78e29fe: Fixed a path traversal vulnerability where a dependency whose manifest name was a scoped path traversal (e.g. @x/../../../<path>) could be written outside node_modules to an attacker-controlled location during pnpm install, even with --ignore-scripts. The isolated linker now validates the package name before using it as a directory name, matching the existing protection in the hoisted linker.
  • 47ef6f0: Fixed switching to and self-updating to pnpm v12. pnpm v12 (the Rust port) ships as the pnpm and @pnpm/exe npm packages whose bins are placeholders replaced at install time by the host's native binary from a @pnpm/exe.<platform>-<arch>[-musl] optional dependency. Because pnpm installs its own engine with --ignore-scripts, that relinking never ran, leaving a non-executable placeholder. pnpm now relinks the native binary itself for v12 (recognizing the new platform-package naming scheme and the native pnpm package), and verifies the native binary's npm registry signature before running it.
  • 36928be: ${...} environment-variable placeholders in the httpProxy, httpsProxy, noProxy, proxy, and noproxy settings are no longer expanded when these settings come from a project's pnpm-workspace.yaml. They now receive the same protection already applied to registry.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.34.4: pnpm 10.34.4

Compare Source

Patch Changes
  • 352ae48: Security: validate config dependency names and versions before using them to build filesystem paths. A pnpm-workspace.yaml with a traversal-shaped configDependencies name (such as ../../PWNED) or version (such as ../../../PWNED) could previously cause pnpm install to create symlinks or write package files outside node_modules/.pnpm-config and the store. Names must now be valid npm package names and versions must be exact semver versions. See GHSA-qrv3-253h-g69c.

  • 352ae48: Reject path-traversal and reserved dependency aliases (such as ../../../escape, .bin, .pnpm, or node_modules) that come from a lockfile rather than a freshly resolved manifest. A crafted lockfile alias could otherwise be joined directly under a hoisted node_modules directory, letting package files be written outside the intended install root or overwrite pnpm-owned layout.

    The nodeLinker: hoisted graph builder now validates each alias at the directory sink (safeJoinModulesDir), matching the validation pnpm already performs when resolving aliases from manifests. See GHSA-fr4h-3cph-29xv.

  • 352ae48: Prevent pnpm patch-remove from removing files outside the configured patches directory.

  • 217fbe0: Hardened the warning printed when a project .npmrc uses environment variables in registry/auth settings: the suggested pnpm config set command is now only included for keys made up of shell-inert characters. Because the key comes from a repository-controlled .npmrc and a shell expands $(...), backticks, and $VAR even inside double quotes, a crafted key could otherwise have turned the suggested copy-paste command into command execution.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.34.3: pnpm 10.34.3

Compare 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 .npmrcregistry, @scope:registry, proxy URLs, URL-scoped keys (//host/…), and credential values (_authToken, _auth, _password, username, tokenHelper, cert, key);
  • registry URLs in pnpm-workspace.yaml.

This release also closes a bypass where a project .npmrc could set userconfig, globalconfig, or prefix to make pnpm load a repo-supplied file as trusted config (via @pnpm/npm-conf@3.0.3).

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 ~/.npmrc instead of the repo. In GitHub Actions, actions/setup-node with registry-url already writes a user-level .npmrc, so NODE_AUTH_TOKEN keeps working. For other CI where editing each pipeline is hard, set NPM_CONFIG_USERCONFIG=.npmrc in the CI environment to declare the project .npmrc trusted.

See https://pnpm.io/npmrc for full migration details.

Patch Changes
  • Improved the warning printed when a project .npmrc uses 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 running pnpm config set "<key>" <value> to store it in the global config, or by keeping the ${...} line in the user-level ~/.npmrc — with a link to https://pnpm.io/npmrc.
  • A repository-controlled project or workspace .npmrc can no longer redirect which files pnpm loads as its trusted user and global configuration. Previously such a file could set userconfig, globalconfig, or prefix to point at an attacker-supplied file shipped in the repository, and pnpm would load it as a trusted config source — bypassing the protection that prevents repository config from expanding environment variables into registry request destinations and credentials, and allowing it to set tokenHelper. The user/global config file locations are now resolved only from trusted sources (CLI options, environment config, the npm builtin config, and defaults) before the project and workspace .npmrc files are read. Fixed by upgrading @pnpm/npm-conf to 3.0.3.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.34.2: pnpm 10.34.2

Compare 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 .npmrcregistry, @scope:registry, proxy URLs, URL-scoped keys (//host/…), and credential values (_authToken, _auth, _password, username, tokenHelper, cert, key);
  • registry URLs in pnpm-workspace.yaml.

This release also closes a bypass where a project .npmrc could set userconfig, globalconfig, or prefix to make pnpm load a repo-supplied file as trusted config (via @pnpm/npm-conf@3.0.3).

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 ~/.npmrc instead of the repo. In GitHub Actions, actions/setup-node with registry-url already writes a user-level .npmrc, so NODE_AUTH_TOKEN keeps working. For other CI where editing each pipeline is hard, set NPM_CONFIG_USERCONFIG=.npmrc in the CI environment to declare the project .npmrc trusted.

See https://pnpm.io/npmrc for full migration details.

Patch Changes
  • Package-manager bootstrap traffic is now resolved through trusted registries and trusted network config. When pnpm downloads the pnpm version requested by a repository's packageManager field, the registry it fetches from (and the proxy/TLS settings used for that traffic) now come exclusively from trusted config sources — CLI options, env config, user and global .npmrc — defaulting to the public npm registry, instead of the repository's project/workspace settings.
  • pnpm now verifies the npm registry signature of a package-manager binary before spawning it. When the packageManager field (or pnpm self-update) makes pnpm download another pnpm version, the staged install is verified corepack-style: the integrity recorded in the staged lockfile must carry a valid npm registry signature for the exact name@version, validated against npm's public signing keys that ship embedded in the pnpm CLI. Verification fails closed — a tampered download, an unsigned package, or an unreachable registry refuses the version switch rather than running an unverified binary. It runs only when the wanted version is actually downloaded (a tools-directory cache miss), so repeated commands pay no extra network round trip.
  • Environment variable expansion is now trust-aware for registry/auth config and request destinations. Repository-controlled config files (the project and workspace .npmrc and pnpm-workspace.yaml) can no longer expand ${...} placeholders in registry/proxy request destinations, URL-scoped keys, or registry credential values, preventing repository-controlled configuration from exfiltrating environment secrets through request URLs. Trusted user/global/CLI/env config keeps full env expansion, so existing token and registry setup flows continue to work.
  • Reject reserved manifest bin names ("", ".", "..", 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 onlyBuiltDependencies (and allowBuilds) entries 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 the key. Lockfile entries are now rejected when 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.
  • pnpm now verifies the detached OpenPGP signature of a Node.js release's SHASUMS256.txt against the Node.js release team's public keys (embedded in the pnpm CLI) before trusting its hashes. The Node.js download mirror is repository-configurable (node-mirror:<channel> in .npmrc), and the integrity check previously trusted a SHASUMS256.txt fetched from that same mirror — a circular check that a malicious mirror could satisfy with a tampered binary and matching hashes. A mirror that proxies the real signed SHASUMS keeps working unchanged. Only the release channel publishes signed SHASUMS files, so pre-release channels (rc, nightly, …) remain unverified.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.34.1: pnpm 10.34.1

Compare Source

Patch Changes
  • Reject pnpm-lock.yaml entries whose remote tarball resolution: block is missing the integrity field. 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 strips integrity:) 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 with ERR_PNPM_MISSING_TARBALL_INTEGRITY. Git-hosted tarballs (gitHosted: true or a URL on codeload.github.com / bitbucket.org / gitlab.com) and file: tarballs are exempt — the commit SHA in a git-host URL and the user-controlled local path already anchor the bytes.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.34.0: pnpm 10.34

Compare Source

Minor Changes
  • Treat tarball-integrity mismatches against the lockfile as a hard failure by default. Previously, pnpm install (non-frozen) would log ERR_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 install now exits with ERR_PNPM_TARBALL_INTEGRITY and 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.

    --force and pnpm update deliberately 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-lockfile behavior is unchanged. --fix-lockfile keeps its documented purpose (filling in missing lockfile entries) and is also not a bypass.

Patch Changes
  • Pin unscoped per-registry settings (_authToken, _auth, username/_password, tokenHelper, inline cert/key) to the registry declared in the same config source at load time, so a later layer overriding registry= (workspace .npmrc, pnpm-workspace.yaml, CLI --registry) cannot redirect a credential or client certificate authored for a different host. A deprecation warning is emitted whenever an unscoped per-registry setting is encountered, naming the source and the URL it was pinned to. Reported by JUNYI LIU.
  • Fixed minimumReleaseAge handling when cached metadata is abbreviated. The npm registry returns abbreviated package metadata (without the per-version time field) by default, which made the maturity check throw ERR_PNPM_MISSING_TIME whenever cached abbreviated metadata was reused. pnpm now upgrades cached abbreviated metadata to the full document via a follow-up fetch when minimumReleaseAge is active, persists the upgrade to the on-disk cache so subsequent installs skip the extra fetch, and lets ERR_PNPM_MISSING_TIME from the cache fast-path fall through to the network fetch even under strict mode.
  • Reject git resolutions whose commit field is not a 40-character hexadecimal SHA before invoking git. A malicious lockfile could otherwise smuggle a value such as --upload-pack=<command> through git fetch / git checkout, which on SSH or local-file transports executes the supplied command.
  • Reject patch files whose diff --git headers reference paths outside the patched package directory. Previously a malicious .patch file added via a pull request could write, delete, or rename arbitrary files reachable by the user running pnpm install.
  • Fixed --prefix=<dir> not being honored when locating the workspace root. The --prefix → dir rename was applied after workspace detection, so workspace settings declared in <dir>/pnpm-workspace.yaml were not loaded when pnpm was invoked from outside <dir> #​11535.
  • Reject dependency aliases that contain path-traversal segments (such as @x/../../../../../.git/hooks) when reading them from a package manifest or symlinking them into node_modules. A malicious registry package could otherwise use a transitive dependency key to make pnpm install create symlinks at attacker-chosen paths outside the intended node_modules directory.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.33.4: pnpm 10.33.4

Compare Source

Patch Changes
  • 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: true field 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.

  • Fix a regression where pnpm --recursive --filter '!<pkg>' run/exec/test/add would include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative --filter arguments are provided, matching the documented behavior. To include the root, pass --include-workspace-root #​11341.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.33.3: pnpm 10.33.3

Compare Source

Patch Changes
  • When self-updating from v10's @pnpm/exe to v11+ on Intel macOS (darwin-x64), pnpm self-update now transparently switches to the JS-only pnpm package on npm instead of installing @pnpm/exe@v11+ (which doesn't ship a working binary for Intel Macs because of an upstream Node.js SEA bug — see #​11423 and nodejs/node#62893). Without this, the self-update would silently leave the user with no working pnpm binary. The new install requires Node.js to be available on PATH; a warning is printed when the swap happens. All other host/version combinations are unchanged.
  • pnpm self-update (with no version argument) no longer downgrades pnpm when the registry's latest dist-tag points to an older release than the currently active version. Run pnpm self-update latest to force a downgrade #​11418.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.33.2: pnpm 10.33.2

Compare Source

Patch Changes
  • Globally-installed bins no longer fail with ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND when pnpm was installed via the standalone @pnpm/exe binary (e.g. curl -fsSL https://get.pnpm.io/install.sh | sh -) on a system without a separate Node.js installation. Previously, when which('node') failed during pnpm add --global, pnpm fell back to process.execPath, which in @pnpm/exe is the pnpm binary itself — and that path was baked into the generated bin shim, causing the shim to invoke pnpm instead of Node #​11291, #​4645.

  • Fix an infinite fork-bomb that could happen when pnpm was installed with one version (e.g. npm install -g pnpm@A) and run inside a project whose package.json selected a different pnpm version via the packageManager field (e.g. pnpm@B), while a pnpm-workspace.yaml also existed at the project root.

    The child's environment is now forced to manage-package-manager-versions=false (v10) and pm-on-fail=ignore (v11+), which disables the package-manager-version handling in whichever pnpm runs as the child.

    Fixes #​11337.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.33.1: pnpm 10.33.1

Compare Source

Patch Changes
  • When a project's packageManager field selects pnpm v11 or newer, commands that v10 would have passed through to npm (version, login, logout, publish, unpublish, deprecate, dist-tag, docs, ping, search, star, stars, unstar, whoami, etc.) are now handed over to the wanted pnpm, which implements them natively. Previously they silently shelled out to npm — making, for example, pnpm version --help print npm's help on a project with packageManager: pnpm@11.0.0-rc.3 #​11328.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.33.0: pnpm 10.33

Compare Source

Minor Changes
  • Added a new dedupePeers setting 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 (foo@1.0.0(bar@2.0.0)). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #​11070.
Patch Changes
  • Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled, while preserving non-frozen CI fallback behavior.

  • When package metadata is malformed or can't be fetched, the error thrown will now show the originating error.

  • Fixed intermittent failures when multiple pnpm dlx calls run concurrently for the same package. When the global virtual store is enabled, the importer now verifies file content before skipping a rename, avoiding destructive swap-renames that break concurrent processes. Also tolerates EPERM during bin creation on Windows and properly propagates enableGlobalVirtualStore through the install pipeline.

  • Fixed handling of non-string version selectors in hoistPeers, preventing invalid peer dependency specifiers.

  • Improve the non-interactive modules purge error hint to include the confirmModulesPurge=false workaround.

    When pnpm needs to recreate node_modules but no TTY is available, the error now suggests either setting CI=true or disabling the purge confirmation prompt via confirmModulesPurge=false.

    Adds a regression test for the non-TTY flow.

  • Fixed false "Command not found" errors on Windows when a command exists in PATH but exits with a non-zero code. Also fixed path resolution for --filter contexts where the command runs in a different package directory.

  • When a pnpm-lock.yaml contains two documents, ignore the first one. pnpm v11 will write two lockfile documents into pnpm-lock.yaml in order to store pnpm version integrities and config dependency resolutions.

  • Fixed a bug preventing the clearCache function returned by createNpmResolver from properly clearing metadata cache.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.32.1: pnpm 10.32.1

Compare Source

Patch Changes
  • Fix a regression where pnpm-workspace.yaml without a packages field caused all directories to be treated as workspace projects. This broke projects that use pnpm-workspace.yaml only for settings (e.g. minimumReleaseAge) without defining workspace packages #​10909.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.32.0: pnpm 10.32

Compare Source

Minor Changes
  • Added --all flag to pnpm approve-builds that approves all pending builds without interactive prompts #​10136.
Patch Changes
  • Reverted change related to setting explicitly the npm config file path, which caused regressions.
  • Reverted fix related to lockfile-include-tarball-url. Fixes #​10915.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.31.0: pnpm 10.31

Compare Source

Minor Changes
  • When pnpm updates the pnpm-workspace.yaml, comments, string formatting, and whitespace will be preserved.
Patch Changes
  • Added -F as a short alias for the --filter option in the help output.

  • Handle undefined pkgSnapshot in pnpm why -r #​10700.

  • Fix headless install not being used when a project has an injected self-referencing file: dependency that resolves to link: in the lockfile.

  • Fixed a race condition when multiple worker threads import the same package to the global virtual store concurrently. The rename operation now tolerates ENOTEMPTY/EEXIST errors if another thread already completed the import.

  • When lockfile-include-tarball-url is set to false, tarball URLs are now always excluded from the lockfile. Previously, tarball URLs could still appear for packages hosted under non-standard URLs, making the behavior flaky and inconsistent #​6667.

  • Fixed optimisticRepeatInstall skipping install when overrides, packageExtensions, ignoredOptionalDependencies, patchedDependencies, or peersSuffixMaxLength changed.

  • Fixed pnpm patch-commit failing with "unable to access '/.config/git/attributes': Permission denied" error in environments where HOME is unset or non-standard (Docker containers, CI systems).

    The issue occurred because pnpm was setting HOME and the Windows user profile env var to empty strings to suppress user git configuration when running git diff. This caused git to resolve the home directory (~) as root (/), leading to permission errors when attempting to access /.config/git/attributes.

    Now uses GIT_CONFIG_GLOBAL: os.devNull instead, which is git's proper mechanism for bypassing user-level configuration without corrupting the home directory path resolution.

    Fixes #​6537

  • Fix pnpm why -r --parseable missing dependents when multiple workspace packages share the same dependency #​8100.

  • Fix link-workspace-packages=true incorrectly linking workspace packages when the requested version doesn't match the workspace package's version. Previously, on fresh installs the version constraint is overridden to * in the fallback resolution paths, causing any workspace package with a matching name to be linked regardless of version #​10173.

  • Fixed pnpm update --interactive table breaking with long version strings (e.g., prerelease versions like 7.0.0-dev.20251209.1) by dynamically calculating column widths instead of using hardcoded values #​10316.

  • Explicitly tell npm the path to the global rc config file.

  • The parameter set by the --allow-build flag is written to allowBuilds.

  • Fix a bug in which specifying filter on pnpm-workspace.yaml would cause pnpm to not detect any projects.

  • Print help message on running pnpm dlx without arguments and exit.

Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.30.3: pnpm 10.30.3

Compare Source

Patch Changes
  • Fixed version switching via packageManager field failing when pnpm is installed as a standalone executable in environments without a system Node.js #​10687.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Workleap
Stackblitz Nx

v10.30.2: pnpm 10.30.2

Compare Source

Patch Changes
  • Fix auto-installed peer dependencies ignoring overrides when a stale version exists in the lockfile.
  • Fixed "input line too long" error on Windows when running lifecycle scripts with the global virtual store enabled #​10673.
  • Update @​zkochan/js-yaml to fix moderate vulnerability.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Workleap
Stackblitz Nx

v10.30.1: pnpm 10.30.1

Compare Source

Patch Changes
  • Use the /-/npm/v1/security/audits/quick endpoint as the primary audit endpoint, falling back to /-/npm/v1/security/audits when it fails #​10649.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Workleap
Stackblitz Nx

v10.30.0: pnpm 10.30

Compare Source

Minor Changes
  • pnpm why now 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.
Patch Changes
  • Revert pnpm why dependency pruning to prefer correctness over memory consumption. Reverted PR: #​7122.
  • Optimize pnpm why and pnpm list performance in workspaces with many importers by sharing the dependency graph and materialization cache across all importers instead of rebuilding them independently for each one #​10596.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Workleap
Stackblitz Nx

v10.29.3: pnpm 10.29.3

Compare Source

Patch Changes
  • Fixed an out-of-memory error in pnpm list (and pnpm why) on large dependency graphs by replacing the recursive tree builder with a two-phase approach: a BFS dependency graph followed by cached tree materialization. Duplicate subtrees are now deduplicated in the output, shown as "deduped (N deps hidden)" #​10586.
  • Fixed allowBuilds not working when set via .pnpmfile.cjs #​10516.
  • When the enableGlobalVirtualStore option is set, the pnpm deploy command would incorrectly create symlinks to the global virtual store. To keep the deploy directory self-contained, pnpm deploy now ignores this setting and always creates a localized virtual store within the deploy directory.
  • Fixed minimumReleaseAgeExclude not being respected by pnpm dlx #​10338.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Workleap
Stackblitz Nx

v10.29.2: pnpm 10.29.2

Compare Source

Patch Changes
  • Reverted a fix shipped in v10.29.1, which caused another issue #​10571.
    Reverted fix: Fixed pnpm run -r failing with "No projects matched the filters" when an empty pnpm-workspace.yaml exists #​10497.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.29.1: pnpm 10.29.1

Compare Source

Minor Changes
  • The pnpm dlx / pnpx command now supports the catalog: protocol. Example: pnpm dlx shx@catalog:.
  • Support configuring auditLevel in the pnpm-workspace.yaml file #​10540.
  • Support bare workspace: protocol without version specifier. It is now treated as workspace:* and resolves to the concrete version during publish #​10436.
Patch Changes
  • Fixed pnpm list --json returning incorrect paths when using global virtual store #​10187.

  • Fix pnpm store path and pnpm store status using workspace root for path resolution when storeDir is relative #​10290.

  • Fixed pnpm run -r failing with "No projects matched the filters" when an empty pnpm-workspace.yaml exists #​10497.

  • Fixed a bug where catalogMode: strict would write the literal string "catalog:" to pnpm-workspace.yaml instead of the resolved version specifier when re-adding an existing catalog dependency #​10176.

  • Fixed the documentation URL shown in pnpm completion --help to point to the correct page at https://pnpm.io/completion #​10281.

  • Skip local file: protocol dependencies during pnpm fetch. This fixes an issue where pnpm fetch would fail in Docker builds when local directory dependencies were not available #​10460.

  • Fixed pnpm audit --json to respect the --audit-level setting for both exit code and output filtering #​10540.

  • update tar to version 7.5.7 to fix security issue

    Updating the version of dependency tar to 7.5.7 because the previous one have a security vulnerability reported here: CVE-2026-24842

  • Fix pnpm audit --fix replacing reference overrides (e.g. $foo) with concrete versions #​10325.

  • Fix shamefullyHoist set via updateConfig in .pnpmfile.cjs not being converted to publicHoistPattern #​10271.

  • pnpm help should correctly report if the currently running pnpm CLI is bundled with Node.js #​10561.

  • Add a warning when the current directory contains the PATH delimiter character. On macOS, folder names containing forward slashes (/) appear as colons (:) at the Unix layer. Since colons are PATH separators in POSIX systems, this breaks PATH injection for node_modules/.bin, causing binaries to not be found when running commands like pnpm exec #​10457.

Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.28.2: pnpm 10.28.2

Compare Source

Patch Changes
  • Security fix: prevent path traversal in directories.bin field.

  • When pnpm installs a file: or git: dependency, it now validates that symlinks point within the package directory. Symlinks to paths outside the package root are skipped to prevent local data from being leaked into node_modules.

    This fixes a security issue where a malicious package could create symlinks to sensitive files (e.g., /etc/passwd, ~/.ssh/id_rsa) and have their contents copied when the package is installed.

    Note: This only affects file: and git: dependencies. Registry packages (npm) have symlinks stripped during publish and are not affected.

  • Fixed optional dependencies to request full metadata from the registry to get the libc field, which is required for proper platform compatibility checks #​9950.

Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.28.1: pnpm 10.28.1

Compare Source

Patch Changes
  • Fixed installation of config dependencies from private registries.

    Added support for object type in configDependencies when the tarball URL returned from package metadata differs from the computed URL #​10431.

  • Fix path traversal vulnerability in binary fetcher ZIP extraction

    • Validate ZIP entry paths before extraction to prevent writing files outside target directory
    • Validate BinaryResolution.prefix (basename) to prevent directory escape via crafted prefix
    • Both attack vectors now throw ERR_PNPM_PATH_TRAVERSAL error
  • Support plain http:// and https:// URLs ending with .git as git repository dependencies.

    Previously, URLs like https://gitea.example.org/user/repo.git#commit were not recognized as git repositories because they lacked the git+ prefix (e.g., git+https://). This caused issues when installing dependencies from self-hosted git servers like Gitea or Forgejo that don't provide tarball downloads.

    Changes:

    • The git resolver now runs before the tarball resolver, ensuring git URLs are handled by the correct resolver
    • The git resolver now recognizes plain http:// and https:// URLs ending in .git as git repositories
    • Removed the isRepository check from the tarball resolver since it's no longer needed with the new resolver order

    Fixes #​10468

  • pnpm run -r and pnpm run --filter now fail with a non-zero exit code when no packages have the specified script. Previously, this only failed when all packages were selected. Use --if-present to suppress this error #​6844.

  • Fixed a path traversal vulnerability in tarball extraction on Windows. The path normalization was only checking for ./ but not .\. Since backslashes are directory separators on Windows, malicious packages could use paths like foo\..\..\.npmrc to write files outside the package directory.

  • When running "pnpm exec" from a subdirectory of a project, don't change the current working directory to the root of the project #​5759.

  • Fixed a path traversal vulnerability in pnpm's bin linking. Bin names starting with @ bypassed validation, and after scope normalization, path traversal sequences like ../../ remained intact.

  • Revert Try to avoid making network calls with preferOffline #​10334.

  • Fix --save-peer to write valid semver ranges to peerDependencies for protocol-based installs (e.g. jsr:) by deriving from resolved versions when available and falling back to * if none is available #​10417.

  • Do not exclude the root workspace project, when it is explicitly selected via a filter #​10465.

Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.28.0: pnpm 10.28

Compare Source

Minor Changes
  • Add support for a hook called beforePacking that can be used to customize the package.json contents at publish time #​3816.
  • In some cases, a filtered install (i.e. pnpm install --filter ...) was slower than running pnpm install without any filter arguments. This performance regression is now fixed. Filtered installs should be as fast or faster than a full install #​10408.
Patch Changes
  • Do not add a symlink to the project into the store's project registry if the store is in a subdirectory of the project #​10411.
  • It should be possible to declare the requiredScripts setting in pnpm-workspace.yaml #​10261.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.27.0: pnpm 10.27

Compare Source

Minor Changes
  • Adding trustPolicyIgnoreAfter allows you to ignore trust policy checks for packages published more than a specified time ago#​10352.

  • Added project registry for global virtual store prune support.

    Projects using the store are now registered via symlinks in {storeDir}/v10/projects/. This enables pnpm store prune to track which packages are still in use by active projects and safely remove unused packages from the global virtual store.

  • 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.

  • Added mark-and-sweep garbage collection for global virtual store.

    pnpm store prune now removes unused packages from the global virtual store's links/ directory. The algorithm:

    1. Scans all registered projects for symlinks pointing to the store
    2. Walks transitive dependencies to mark reachable packages
    3. Removes any package directories not marked as reachable

    This includes support for workspace monorepos - all node_modules directories within a project (including those in workspace packages) are scanned.

Patch Changes
  • Throw an error if the value of the tokenHelper or <url>:tokenHelper setting contains an environment variable.
  • Git dependencies with build scripts should respect the dangerouslyAllowAllBuilds settings #​10376.
  • Skip the package manager check when running with --global and a project packageManager is configured, and warn that the check is skipped.
  • pnpm store prune should not fail if the dlx cache directory has files, not only directories #​10384
  • Fixed a bug (#​9759) where pnpm add would incorrectly modify a catalog entry in pnpm-workspace.yaml to its exact version.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.26.2: pnpm 10.26.2

Compare Source

Patch Changes
  • Improve error message when a package version exists but does not meet the minimumReleaseAge constraint. The error now clearly states that the version exists and shows a human-readable time since release (e.g., "released 6 hours ago") #​10307.

  • Fix installation of Git dependencies using annotated tags #​10335.

    Previously, pnpm would store the annotated tag object's SHA in the lockfile instead of the actual commit SHA. This caused ERR_PNPM_GIT_CHECKOUT_FAILED errors because the checked-out commit hash didn't match the stored tag object hash.

  • Binaries of runtime engines (Node.js, Deno, Bun) are written to node_modules/.bin before lifecycle scripts (install, postinstall, prepare) are executed #​10244.

  • Try to avoid making network calls with preferOffline #​10334.

Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.26.1: pnpm 10.26.1

Compare Source

Patch Changes
  • Don't fail on pnpm add, when blockExoticSubdeps is set to true #​10324.
  • Always resolve git references to full commits and ensure HEAD points to the commit after checkout #​10310.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.26.0: pnpm 10.26

Compare Source

Minor Changes
  • Semi-breaking. Block git-hosted dependencies from running prepare scripts unless explicitly allowed in onlyBuiltDependencies #​10288.

  • Semi-breaking. 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 a new setting blockExoticSubdeps that prevents the resolution of exotic protocols in transitive dependencies.

    When set to true, direct dependencies (those listed in your root package.json) may still use exotic sources, but all transitive dependencies must be resolved from a trusted source. Trusted sources include the configured registry, local file paths, workspace links, trusted GitHub repositories (node, bun, deno), and custom resolvers.

    This helps to secure the dependency supply chain. Packages from trusted sources are considered safer, as they are typically subject to more reliable verification and scanning for malware and vulnerabilities.

    Exotic sources are dependency locations that bypass the usual trusted resolution process. These protocols are specifically targeted and blocked: Git repositories (git+ssh://...) and direct URL links to tarballs (https://.../package.tgz).

    Related PR: #​10265.

  • Added support for allowBuilds, which is a new field that can be used instead of onlyBuiltDependencies and ignoredBuiltDependencies. The new allowBuilds field in your pnpm-workspace.yaml uses a map of package matchers to explicitly allow (true) or disallow (false) script execution. This allows for a single, easy-to-manage source of truth for your build permissions.

    Example Usage. To explicitly allow all versions of esbuild to run scripts and prevent core-js from running them:

    allowBuilds:
      esbuild: true
      core-js: false
    

    The example above achieves the same result as the previous configuration:

    onlyBuiltDependencies:
      - esbuild
    ignoredBuiltDependencies:
      - core-js
    

    Related PR: #​10311

  • Added support for --dry-run to the pack command #​10301.

Patch Changes
  • Show deprecation in table/list formats when latest version is deprecated #​8658.
  • Remove the injectWorkspacePackages setting from the lockfile on the deploy command #​10294.
  • Normalize the tarball URLs before saving them to the lockfile. URLs should not contain default ports, like :80 for http and :443 for https #​10273.
  • When a dependency is installed via a direct URL that redirects to another URL and is immutable, the original URL is normalized and saved to package.json #​10197.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.25.0: pnpm 10.25

Compare Source

Minor Changes
  • Allow loading certificates from cert, ca, and key for specific registry URLs. E.g., //registry.example.com/:ca=-----BEGIN CERTIFICATE-----.... Previously this was only working via certfile, cafile, and keyfile.

    These properties are supported in .npmrc, but were ignored by pnpm, this will make pnpm read and use them as well.

    Related PR: #​10230.

  • Added a new flag called --bare to pnpm init for creating a package.json with the bare minimum of required fields #​10226.

Patch Changes
  • Improved reporting of ignored dependency scripts #​10276.
  • pnpm install should build any dependencies that were added to onlyBuiltDependencies and were not built yet #​10256.
  • pnpm publish -r --force should allow to run publish over already existing versions in the registry #​10272.
  • Don't fail with a ERR_PNPM_MISSING_TIME error if a package that is excluded from trust policy checks is missing the time field in the metadata.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.24.0: pnpm 10.24

Compare Source

Minor Changes
  • Increased network concurrency on machines with many CPU cores. pnpm now automatically selects a network concurrency between 16 and 64, based on the number of pnpm workers (calculated as workers × 3). This improves performance on high-core systems #​10068.
Patch Changes
  • trustPolicy should ignore the trust evidences of prerelease versions, when installing a non-prerelease version.
  • Handle ENOENT errors thrown by fs.linkSync(), which can occur in containerized environments (OverlayFS) instead of EXDEV. The operation now gracefully falls back to fs.copyFileSync() in these cases #​10217.
  • Reverted: pnpm self-update should download pnpm from the configured npm registry #​10205.
  • Packages that don't have a package.json file (like Node.js) should not be reimported from the store on every install. Another file from the package should be checked in order to verify its presence in node_modules.
  • Correctly read auth tokens for URLs that contain underscores #​17.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.23.0: pnpm 10.23

Compare Source

Minor Changes
  • Added --lockfile-only option to pnpm list #​10020.
Patch Changes
  • pnpm self-update should download pnpm from the configured npm registry #​10205.
  • pnpm self-update should always install the non-executable pnpm package (pnpm in the registry) and never the @pnpm/exe package, when installing v11 or newer. We currently cannot ship @pnpm/exe as pkg doesn't work with ESM #​10190.
  • Node.js runtime is not added to "dependencies" on pnpm add, if there's a engines.runtime setting declared in package.json #​10209.
  • The installation should fail if an optional dependency cannot be installed due to a trust policy check failure #​10208.
  • pnpm list and pnpm why now display npm: protocol for aliased packages (e.g., foo npm:is-odd@3.0.1) #​8660.
  • Don't add an extra slash to the Node.js mirror URL #​10204.
  • pnpm store prune should not fail if the store contains Node.js packages #​10131.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.22.0: pnpm 10.22

Compare Source

Minor Changes
  • Added support for trustPolicyExclude #​10164.

    You can now list one or more specific packages or versions that pnpm should allow to install, even if those packages don't satisfy the trust policy requirement. For example:

    trustPolicy: no-downgrade
    trustPolicyExclude:
      - chokidar@4.0.3
      - webpack@4.47.0 || 5.102.1
    
  • Allow to override the engines field on publish by the publishConfig.engines field.

Patch Changes
  • Don't crash when two processes of pnpm are hardlinking the contents of a directory to the same destination simultaneously #​10179.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.21.0: pnpm 10.21

Compare Source

Minor Changes
  • Node.js Runtime Installation for Dependencies. 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 "engines" field. For example:

    {
      "engines": {
        "runtime": {
          "name": "node",
          "version": "^24.11.0",
          "onFail": "download"
        }
      }
    }
    

    If the package with the Node.js runtime dependency is a CLI app, pnpm will bind the CLI app to the required Node.js version. This ensures that, regardless of the globally installed Node.js instance, the CLI will use the compatible version of Node.js.

    If the package has a postinstall script, that script will be executed using the specified Node.js version.

    Related PR: #​10141

  • Added a new setting: trustPolicy.

    When set to no-downgrade, pnpm will fail installation if a package’s trust level has decreased compared to previous releases — for example, if it was previously published by a trusted publisher but now only has provenance or no trust evidence.
    This helps prevent installing potentially compromised versions of a package.

    Related issue: #​8889.

  • Added support for pnpm config get globalconfig to retrieve the global config file path #​9977.

Patch Changes
  • When a user runs pnpm update on a dependency that is not directly listed in package.json, none of the direct dependencies should be updated #​10155.
  • Don't crash when two processes of pnpm are hardlinking the contents of a directory to the same destination simultaneously #​10160.
  • Setting gitBranchLockfile and related settings via pnpm-workspace.yaml should work #​9651.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.20.0: pnpm 10.20

Compare Source

Minor Changes
  • Support --all option in pnpm --help to list all commands #​8628.
Patch Changes
  • When the latest version doesn't satisfy the maturity requirement configured by minimumReleaseAge, pick the highest version that is mature enough, even if it has a different major version #​10100.
  • create command should not verify patch info.
  • Set managePackageManagerVersions to false, when switching to a different version of pnpm CLI, in order to avoid subsequent switches #​10063.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.19.0: pnpm 10.19

Compare Source

Minor Changes
  • You can now allow specific versions of dependencies to run postinstall scripts. onlyBuiltDependencies now accepts package names with lists of trusted versions. For example:

    onlyBuiltDependencies:
      - nx@21.6.4 || 21.6.5
      - esbuild@0.25.1
    

    Related PR: #​10104.

  • Added support for exact versions in minimumReleaseAgeExclude #​9985.

    You can now list one or more specific versions that pnpm should allow to install, even if those versions don’t satisfy the maturity requirement set by minimumReleaseAge. For example:

    minimumReleaseAge: 1440
    minimumReleaseAgeExclude:
      - nx@21.6.5
      - webpack@4.47.0 || 5.102.1
    
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.18.3: pnpm 10.18.3

Compare Source

Patch Changes
  • Fix a bug where pnpm would infinitely recurse when using verifyDepsBeforeInstall: install and pre/post install scripts that called other pnpm scripts #​10060.
  • Fixed scoped registry keys (e.g., @scope:registry) being parsed as property paths in pnpm config get when --location=project is used #​9362.
  • Remove pnpm-specific CLI options before passing to npm publish to prevent "Unknown cli config" warnings #​9646.
  • Fixed EISDIR error when bin field points to a directory #​9441.
  • Preserve version and hasBin for variations packages #​10022.
  • Fixed pnpm config set --location=project incorrectly handling keys with slashes (auth tokens, registry settings) #​9884.
  • When both pnpm-workspace.yaml and .npmrc exist, pnpm config set --location=project now writes to pnpm-workspace.yaml (matching read priority) #​10072.
  • Prevent a table width error in pnpm outdated --long #​10040.
  • Sync bin links after injected dependencies are updated by build scripts. This ensures that binaries created during build processes are properly linked and accessible to consuming projects #​10057.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.18.2: pnpm 10.18.2

Compare Source

Patch Changes
  • pnpm outdated --long should work #​10040.
  • Replace ndjson with split2. Reduce the bundle size of pnpm CLI #​10054.
  • pnpm dlx should request the full metadata of packages, when minimumReleaseAge is set #​9963.
  • pnpm version switching should work when the pnpm home directory is in a symlinked directory #​9715.
  • Fix EPIPE errors when piping output to other commands #​10027.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.18.1: pnpm 10.18.1

Compare Source

Patch Changes
  • Don't print a warning, when --lockfile-only is used #​8320.
  • pnpm setup creates a command shim to the pnpm executable. This is needed to be able to run pnpm self-update on Windows #​5700.
  • When using pnpm catalogs and running a normal pnpm install, pnpm produced false positive warnings for "skip adding to the default catalog because it already exists". This warning now only prints when using pnpm add --save-catalog as originally intended.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.18.0: pnpm 10.18

Compare Source

Minor Changes
  • Added network performance monitoring to pnpm by implementing warnings for slow network requests, including both metadata fetches and tarball downloads.

    Added configuration options for warning thresholds: fetchWarnTimeoutMs and fetchMinSpeedKiBps.
    Warning messages are displayed when requests exceed time thresholds or fall below speed minimums

    Related PR: #​10025.

Patch Changes
  • Retry filesystem operations on EAGAIN errors #​9959.
  • Outdated command respects minimumReleaseAge configuration #​10030.
  • Correctly apply the cleanupUnusedCatalogs configuration when removing dependent packages.
  • Don't fail with a meaningless error when scriptShell is set to false #​8748.
  • pnpm dlx should not fail when minimumReleaseAge is set #​10037.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.17.1: pnpm 10.17.1

Compare Source

Patch Changes
  • When a version specifier cannot be resolved because the versions don't satisfy the minimumReleaseAge setting, print this information out in the error message #​9974.
  • Fix state.json creation path when executing pnpm patch in a workspace project #​9733.
  • When minimumReleaseAge is set and the latest tag is not mature enough, prefer a non-deprecated version as the new latest #​9987.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.17.0: pnpm 10.17

Compare Source

Minor Changes
  • The minimumReleaseAgeExclude setting now supports patterns. For instance:

    minimumReleaseAge: 1440
    minimumReleaseAgeExclude:
      - "@eslint/*"
    

    Related PR: #​9984.

Patch Changes
  • Don't ignore the minimumReleaseAge check, when the package is requested by exact version and the packument is loaded from cache #​9978.
  • When minimumReleaseAge is set and the active version under a dist-tag is not mature enough, do not downgrade to a prerelease version in case the original version wasn't a prerelease one #​9979.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.16.1: pnpm 10.16.1

Compare Source

Patch Changes
  • The full metadata cache should be stored not at the same location as the abbreviated metadata. This fixes a bug where pnpm was loading the abbreviated metadata from cache and couldn't find the "time" field as a result #​9963.
  • Forcibly disable ANSI color codes when generating patch diff #​9914.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.16.0: pnpm 10.16

Compare Source

Minor Changes
  • There have been several incidents recently where popular packages were successfully attacked. To reduce the risk of installing a compromised version, we are introducing a new setting that delays the installation of newly released dependencies. In most cases, such attacks are discovered quickly and the malicious versions are removed from the registry within an hour.

    The new setting is called minimumReleaseAge. It specifies the number of minutes that must pass after a version is published before pnpm will install it. For example, setting minimumReleaseAge: 1440 ensures that only packages released at least one day ago can be installed.

    If you set minimumReleaseAge but need to disable this restriction for certain dependencies, you can list them under the minimumReleaseAgeExclude setting. For instance, with the following configuration pnpm will always install the latest version of webpack, regardless of its release time:

    minimumReleaseAgeExclude:
      - webpack
    

    Related issue: #​9921.

  • Added support for finders #​9946.

    In the past, pnpm list and pnpm why could only search for dependencies by name (and optionally version). For example:

    pnpm why minimist
    

    prints the chain of dependencies to any installed instance of minimist:

    verdaccio 5.20.1
    ├─┬ handlebars 4.7.7
    │ └── minimist 1.2.8
    └─┬ mv 2.1.1
      └─┬ mkdirp 0.5.6
        └── minimist 1.2.8
    

    What if we want to search by other properties of a dependency, not just its name? For instance, find all packages that have react@17 in their peer dependencies?

    This is now possible with "finder functions". Finder functions can be declared in .pnpmfile.cjs and invoked with the --find-by=<function name> flag when running pnpm list or pnpm why.

    Let's say we want to find any dependencies that have React 17 in peer dependencies. We can add this finder to our .pnpmfile.cjs:

    module.exports = {
      finders: {
        react17: (ctx) => {
          return ctx.readManifest().peerDependencies?.react === "^17.0.0";
        },
      },
    };
    

    Now we can use this finder function by running:

    pnpm why --find-by=react17
    

    pnpm will find all dependencies that have this React in peer dependencies and print their exact locations in the dependency graph.

    @apollo/client 4.0.4
    ├── @graphql-typed-document-node/core 3.2.0
    └── graphql-tag 2.12.6
    

    It is also possible to print out some additional information in the output by returning a string from the finder. For example, with the following finder:

    module.exports = {
      finders: {
        react17: (ctx) => {
          const manifest = ctx.readManifest();
          if (manifest.peerDependencies?.react === "^17.0.0") {
            return `license: ${manifest.license}`;
          }
          return false;
        },
      },
    };
    

    Every matched package will also print out the license from its package.json:

    @apollo/client 4.0.4
    ├── @graphql-typed-document-node/core 3.2.0
    │   license: MIT
    └── graphql-tag 2.12.6
        license: MIT
    
Patch Changes
  • Fix deprecation warning printed when executing pnpm with Node.js 24 #​9529.
  • Throw an error if nodeVersion is not set to an exact semver version #​9934.
  • pnpm publish should be able to publish a .tar.gz file #​9927.
  • Canceling a running process with Ctrl-C should make pnpm run return a non-zero exit code #​9626.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.15.1: pnpm 10.15.1

Compare Source

Patch Changes
  • Fix .pnp.cjs crash when importing subpath #​9904.
  • When resolving peer dependencies, pnpm looks whether the peer dependency is present in the root workspace project's dependencies. This change makes it so that the peer dependency is correctly resolved even from aliased npm-hosted dependencies or other types of dependencies #​9913.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.15.0: pnpm 10.15

Compare Source

Minor Changes
  • Added the cleanupUnusedCatalogs configuration. When set to true, pnpm will remove unused catalog entries during installation #​9793.
  • Automatically load pnpmfiles from config dependencies that are named @*/pnpm-plugin-* #​9780.
  • pnpm config get now prints an INI string for an object value #​9797.
  • pnpm config get now accepts property paths (e.g. pnpm config get catalog.react, pnpm config get .catalog.react, pnpm config get 'packageExtensions["@babel/parser"].peerDependencies["@babel/types"]'), and pnpm config set now accepts dot-leading or subscripted keys (e.g. pnpm config set .ignoreScripts true).
  • pnpm config get --json now prints a JSON serialization of config value, and pnpm config set --json now parses the input value as JSON.
Patch Changes
  • Semi-breaking. When automatically installing missing peer dependencies, prefer versions that are already present in the direct dependencies of the root workspace package #​9835.
  • When executing the pnpm create command, must verify whether the node version is supported even if a cache already exists #​9775.
  • When making requests for the non-abbreviated packument, add */* to the Accept header to avoid getting a 406 error on AWS CodeArtifact #​9862.
  • The standalone exe version of pnpm works with glibc 2.26 again #​9734.
  • Fix a regression in which pnpm dlx pkg --help doesn't pass --help to pkg #​9823.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.14.0: pnpm 10.14

Compare Source

Minor Changes
  • Added support for JavaScript runtime installation

    Declare Node.js, Deno, or Bun in devEngines.runtime (inside package.json) and let pnpm download and pin it automatically.

    Usage example:

    {
      "devEngines": {
        "runtime": {
          "name": "node",
          "version": "^24.4.0",
          "onFail": "download" // we only support the "download" value for now
        }
      }
    }
    

    How it works:

    1. pnpm install resolves your specified range to the latest matching runtime version.
    2. The exact version (and checksum) is saved in the lockfile.
    3. Scripts use the local runtime, ensuring consistency across environments.

    Why this is better:

    1. This new setting supports also Deno and Bun (vs. our Node-only settings useNodeVersion and executionEnv.nodeVersion)
    2. Supports version ranges (not just a fixed version).
    3. The resolved version is stored in the pnpm lockfile, along with an integrity checksum for future validation of the Node.js content's validity.
    4. It can be used on any workspace project (like executionEnv.nodeVersion). So, different projects in a workspace can use different runtimes.
    5. For now devEngines.runtime setting will install the runtime locally, which we will improve in future versions of pnpm by using a shared location on the computer.

    Related PR: #​9755.

  • Add --cpu, --libc, and --os to pnpm install, pnpm add, and pnpm dlx to customize supportedArchitectures via the CLI #​7510.

Patch Changes
  • Fix a bug in which pnpm add downloads packages whose libc differ from pnpm.supportedArchitectures.libc.
  • The integrities of the downloaded Node.js artifacts are verified #​9750.
  • Allow dlx to parse CLI flags and options between the dlx command and the command to run or between the dlx command and -- #​9719.
  • pnpm install --prod should removing hoisted dev dependencies #​9782.
  • Fix an edge case bug causing local tarballs to not re-link into the virtual store. This bug would happen when changing the contents of the tarball without renaming the file and running a filtered install.
  • Fix a bug causing pnpm install to incorrectly assume the lockfile is up to date after changing a local tarball that has peers dependencies.
Platinum Sponsors
Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.13.1: pnpm 10.13.1

Compare Source

Patch Changes
  • Run user defined pnpmfiles after pnpmfiles of plugins.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.13.0: pnpm 10.13

Compare Source

Minor Changes
  • Added the possibility to load multiple pnpmfiles. The pnpmfile setting can now accept a list of pnpmfile locations #​9702.

  • pnpm will now automatically load the pnpmfile.cjs file from any config dependency named @pnpm/plugin-* or pnpm-plugin-* #​9729.

    The order in which config dependencies are initialized should not matter — they are initialized in alphabetical order. If a specific order is needed, the paths to the pnpmfile.cjs files in the config dependencies can be explicitly listed using the pnpmfile setting in pnpm-workspace.yaml.

Patch Changes
  • When patching dependencies installed via pkg.pr.new, treat them as Git tarball URLs #​9694.
  • Prevent conflicts between local projects' config and the global config in dangerouslyAllowAllBuilds, onlyBuiltDependencies, onlyBuiltDependenciesFile, and neverBuiltDependencies #​9628.
  • Sort keys in pnpm-workspace.yaml with deep #​9701.
  • The pnpm rebuild command should not add pkgs included in ignoredBuiltDependencies to ignoredBuilds in node_modules/.modules.yaml #​9338.
  • Replaced shell-quote with shlex for quoting command arguments #​9381.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.12.4: pnpm 10.12.4

Compare Source

Patch Changes
  • Fix pnpm licenses command for local dependencies #​9583.
  • Fix a bug in which pnpm ls --filter=not-exist --json prints nothing instead of an empty array #​9672.
  • Fix a deadlock that sometimes happens during peer dependency resolution #​9673.
  • Running pnpm install after pnpm fetch should hoist all dependencies that need to be hoisted.
    Fixes a regression introduced in v10.12.2 by #​9648; resolves #​9689.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.12.3: pnpm 10.12.3

Compare Source

Patch Changes
  • Restore hoisting of optional peer dependencies when installing with an outdated lockfile.
    Regression introduced in v10.12.2 by #​9648; resolves #​9685.

Platinum Sponsors
Bit Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.12.2: pnpm 10.12.2

Compare Source

Patch Changes
  • Fixed hoisting with enableGlobalVirtualStore set to true #​9648.
  • Fix the --help and -h flags not working as expected for the pnpm create command.
  • The dependency package path output by the pnpm licenses list --json command is incorrect.
  • Fix a bug in which pnpm deploy fails due to overridden dependencies having peer dependencies causing ERR_PNPM_OUTDATED_LOCKFILE #​9595.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.12.1: pnpm 10.12.1

Minor Changes
  • Experimental. Added support for global virtual stores. When enabled, node_modules contains only symlinks to a central virtual store, rather than to node_modules/.pnpm. By default, this central store is located at <store-path>/links (you can find the store path by running pnpm store path).

    In the central virtual store, each package is hard linked into a directory whose name is the hash of its dependency graph. This allows multiple projects on the system to symlink shared dependencies from this central location, significantly improving installation speed when a warm cache is available.

    This is conceptually similar to how NixOS manages packages, using dependency graph hashes to create isolated and reusable package directories.

    To enable the global virtual store, set enableGlobalVirtualStore: true in your root pnpm-workspace.yaml, or globally via:

    pnpm config -g set enable-global-virtual-store true
    

    NOTE: In CI environments, where caches are typically cold, this setting may slow down installation. pnpm automatically disables the global virtual store when running in CI.

    Short demo of the speed of installation with this new setting enabled: https://www.youtube.com/watch?v=pNDFfJvaubY&ab_channel=pnpm

    Related PR: #​8190

  • The pnpm update command now supports updating catalog: protocol dependencies and writes new specifiers to pnpm-workspace.yaml.

  • A new catalogMode setting is available for controlling if and how dependencies are added to the default catalog. It can be configured to several modes:

    • strict: Only allows dependency versions from the catalog. Adding a dependency outside the catalog's version range will cause an error.
    • prefer: Prefers catalog versions, but will fall back to direct dependencies if no compatible version is found.
    • manual (default): Does not automatically add dependencies to the catalog.
  • Added two new CLI options (--save-catalog and --save-catalog-name=<name>) to pnpm add to save new dependencies as catalog entries. catalog: or catalog:<name> will be added to package.json and the package specifier will be added to the catalogs or catalog[<name>] object in pnpm-workspace.yaml #​9425.

  • Semi-breaking. The keys used for side-effects caches have changed. If you have a side-effects cache generated by a previous version of pnpm, the new version will not use it and will create a new cache instead #​9605.

  • Added a new setting called ci for explicitly telling pnpm if the current environment is a CI or not.

Patch Changes
  • Sort versions printed by pnpm patch using semantic versioning rules.
  • Improve the way the error message displays mismatched specifiers. Show differences instead of 2 whole objects #​9598.
  • Revert #​9574 to fix a regression #​9596.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord CodeRabbit Workleap
Stackblitz Vite

v10.11.1: pnpm 10.11.1

Compare Source

Patch Changes
  • Fix an issue in which pnpm deploy --legacy creates unexpected directories when the root package.json has a workspace package as a peer dependency #​9550.
  • Dependencies specified via a URL that redirects will only be locked to the target if it is immutable, fixing a regression when installing from GitHub releases. (#​9531)
  • Installation should not exit with an error if strictPeerDependencies is true but all issues are ignored by peerDependencyRules #​9505.
  • Use pnpm_config_ env variables instead of npm_config_ #​9571.
  • Fix a regression (in v10.9.0) causing the --lockfile-only flag on pnpm update to produce a different pnpm-lock.yaml than an update without the flag.
  • Let pnpm deploy work in repos with overrides when inject-workspace-packages=true #​9283.
  • Fixed the problem of path loss caused by parsing URL address. Fixes a regression shipped in pnpm v10.11 via #​9502.
  • pnpm -r --silent run should not print out section #​9563.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.11.0: pnpm 10.11

Compare Source

Minor Changes
  • A new setting added for pnpm init to create a package.json with type=module, when init-type is module. Works as a flag for the init command too #​9463.

  • Added support for Nushell to pnpm setup #​6476.

  • Added two new flags to the pnpm audit command, --ignore and --ignore-unfixable #​8474.

    Ignore all vulnerabilities that have no solution:

    > pnpm audit --ignore-unfixable
    

    Provide a list of CVE's to ignore those specifically, even if they have a resolution.

    > pnpm audit --ignore=CVE-2021-1234 --ignore=CVE-2021-5678
    
  • Added support for recursively running pack in every project of a workspace #​4351.

    Now you can run pnpm -r pack to pack all packages in the workspace.

Patch Changes
  • pnpm version management should work, when dangerouslyAllowAllBuilds is set to true #​9472.
  • pnpm link should work from inside a workspace #​9506.
  • Set the default workspaceConcurrency to Math.min(os.availableParallelism(), 4) #​9493.
  • Installation should not exit with an error if strictPeerDependencies is true but all issues are ignored by peerDependencyRules #​9505.
  • Read updateConfig from pnpm-workspace.yaml #​9500.
  • Add support for recursive pack
  • Remove url.parse usage to fix warning on Node.js 24 #​9492.
  • pnpm run should be able to run commands from the workspace root, if ignoreScripts is set tot true #​4858.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.10.0: pnpm 10.10

Compare Source

Minor Changes
  • Allow loading the preResolution, importPackage, and fetchers hooks from local pnpmfile.
Patch Changes
  • Fix cd command, when shellEmulator is true #​7838.
  • Sort keys in pnpm-workspace.yaml #​9453.
  • Pass the npm_package_json environment variable to the executed scripts #​9452.
  • Fixed a mistake in the description of the --reporter=silent option.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.9.0: pnpm 10.9

Compare Source

Minor Changes
  • Added support for installing JSR packages. You can now install JSR packages using the following syntax:

    pnpm add jsr:<pkg_name>
    

    or with a version range:

    pnpm add jsr:<pkg_name>@<range>
    

    For example, running:

    pnpm add jsr:@foo/bar
    

    will add the following entry to your package.json:

    {
      "dependencies": {
        "@foo/bar": "jsr:^0.1.2"
      }
    }
    

    When publishing, this entry will be transformed into a format compatible with npm, older versions of Yarn, and previous pnpm versions:

    {
      "dependencies": {
        "@foo/bar": "npm:@jsr/foo__bar@^0.1.2"
      }
    }
    

    Related issue: #​8941.

    Note: The @jsr scope defaults to https://npm.jsr.io/ if the @jsr:registry setting is not defined.

  • Added a new setting, dangerouslyAllowAllBuilds, for automatically running any scripts of dependencies without the need to approve any builds. It was already possible to allow all builds by adding this to pnpm-workspace.yaml:

    neverBuiltDependencies: []
    

    dangerouslyAllowAllBuilds has the same effect but also allows to be set globally via:

    pnpm config set dangerouslyAllowAllBuilds true
    

    It can also be set when running a command:

    pnpm install --dangerously-allow-all-builds
    
Patch Changes
  • Fix a false negative in verifyDepsBeforeRun when nodeLinker is hoisted and there is a workspace package without dependencies and node_modules directory #​9424.
  • Explicitly drop verifyDepsBeforeRun support for nodeLinker: pnp. Combining verifyDepsBeforeRun and nodeLinker: pnp will now print a warning.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.8.1: pnpm 10.8.1

Compare Source

Patch Changes
  • Removed bright white highlighting, which didn't look good on some light themes #​9389.
  • If there is no pnpm related configuration in package.json, onlyBuiltDependencies will be written to pnpm-workspace.yaml file #​9404.
  • The patch file path saved by the pnpm patch-commit and patch-remove commands should be a relative path #​9403.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.8.0: pnpm 10.8

Compare Source

Minor Changes
  • Experimental. A new hook is supported for updating configuration settings. The hook can be provided via .pnpmfile.cjs. For example:

    module.exports = {
      hooks: {
        updateConfig: (config) => ({
          ...config,
          nodeLinker: "hoisted",
        }),
      },
    };
    
  • Now you can use the pnpm add command with the --config flag to install new configurational dependencies #​9377.

Patch Changes
  • Do not hang indefinitely, when there is a glob that starts with !/ in pnpm-workspace.yaml. This fixes a regression introduced by #​9169.
  • pnpm audit --fix should update the overrides in pnpm-workspace.yaml.
  • pnpm link should update overrides in pnpm-workspace.yaml, not in package.json #​9365.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.7.1: pnpm 10.7.1

Compare Source

Patch Changes
  • pnpm config set should convert the settings to their correct type before adding them to pnpm-workspace.yaml #​9355.
  • pnpm config get should read auth related settings via npm CLI #​9345.
  • Replace leading ~/ in a path in .npmrc with the home directory #​9217.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.7.0: pnpm 10.7

Compare Source

Minor Changes
  • pnpm config get and list also show settings set in pnpm-workspace.yaml files #​9316.

  • It should be possible to use env variables in pnpm-workspace.yaml setting names and value.

  • Add an ability to patch dependencies by version ranges. Exact versions override version ranges, which in turn override name-only patches. Version range * is the same as name-only, except that patch application failure will not be ignored.

    For example:

    patchedDependencies:
      foo: patches/foo-1.patch
      foo@^2.0.0: patches/foo-2.patch
      foo@2.1.0: patches/foo-3.patch
    

    The above configuration would apply patches/foo-3.patch to foo@2.1.0, patches/foo-2.patch to all foo versions which satisfy ^2.0.0 except 2.1.0, and patches/foo-1.patch to the remaining foo versions.

    [!WARNING]
    The version ranges should not overlap. If you want to specialize a sub range, make sure to exclude it from the other keys. For example:

    # pnpm-workspace.yaml
    patchedDependencies:
      # the specialized sub range
      'foo@2.2.0-2.8.0': patches/foo.2.2.0-2.8.0.patch
      # the more general patch, excluding the sub range above
      'foo@>=2.0.0 <2.2.0 || >2.8.0': 'patches/foo.gte2.patch
    

    In most cases, however, it's sufficient to just define an exact version to override the range.

  • pnpm config set --location=project saves the setting to a pnpm-workspace.yaml file if no .npmrc file is present in the directory #​9316.

  • Rename pnpm.allowNonAppliedPatches to pnpm.allowUnusedPatches. The old name is still supported but it would print a deprecation warning message.

  • Add pnpm.ignorePatchFailures to manage whether pnpm would ignore patch application failures.

    If ignorePatchFailures is not set, pnpm would throw an error when patches with exact versions or version ranges fail to apply, and it would ignore failures from name-only patches.

    If ignorePatchFailures is explicitly set to false, pnpm would throw an error when any type of patch fails to apply.

    If ignorePatchFailures is explicitly set to true, pnpm would print a warning when any type of patch fails to apply.

Patch Changes
  • Remove dependency paths from audit output to prevent out-of-memory errors #​9280.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.6.5: pnpm 10.6.5

Compare Source

Patch Changes
  • Remove warnings after having explicitly approved no builds #​9296.
  • When installing different dependency packages, should retain the ignoredBuilds field in the .modules.yaml file #​9240.
  • Fix usages of the catalog: protocol in injected local workspace packages. This previously errored with ERR_PNPM_SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER. #​8715
  • Setting workspace-concurrency to less than or equal to 0 should work #​9297.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.6.4: pnpm 10.6.4

Compare Source

Patch Changes
  • Fix pnpm dlx with --allow-build flag #​9263.
  • Invalid Node.js version in use-node-version should not cause pnpm itself to break #​9276.
  • The max amount of workers running for linking packages from the store has been reduced to 4 to achieve optimal results #​9286. The workers are performing many file system operations, so increasing the number of CPUs doesn't help performance after some point.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.6.3: pnpm 10.6.3

Compare Source

Patch Changes
  • pnpm install --prod=false should not crash, when executed in a project with a pnpm-workspace.yaml file #​9233. This fixes regression introduced via #​9211.

  • Add the missing node-options config to recursive run #​9180.

  • Removed a branching code path that only executed when dedupe-peer-dependents=false. We believe this internal refactor will not result in behavior changes, but we expect it to make future pnpm versions behave more consistently for projects that override dedupe-peer-dependents to false. There should be less unique bugs from turning off dedupe-peer-dependents.

    See details in #​9259.

Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.6.2: pnpm 10.6.2

Compare Source

Patch Changes
  • pnpm self-update should always update the version in the packageManager field of package.json.
  • Fix running pnpm CLI from pnpm CLI on Windows when the CLI is bundled to an executable #​8971.
  • pnpm patch-commit will now use the same filesystem as the store directory to compare and create patch files.
  • Don't show info output when --loglevel=error is used.
  • peerDependencyRules should be set in pnpm-workspace.yaml to take effect.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.6.1: pnpm 10.6.1

Compare Source

Patch Changes
  • The pnpm CLI process should not stay hanging, when --silent reporting is used.
  • When --loglevel is set to error, don't show installation summary, execution time, and big tarball download progress.
  • Don't ignore pnpm.patchedDependencies from package.json #​9226.
  • When executing the approve-builds command, if package.json contains onlyBuiltDependencies or ignoredBuiltDependencies, the selected dependency package will continue to be written into package.json.
  • When a package version cannot be found in the package metadata, print the registry from which the package was fetched.
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.6.0: pnpm 10.6

Compare Source

Minor Changes
  • pnpm-workspace.yaml can now hold all the settings that .npmrc accepts. The settings should use camelCase #​9211.

    pnpm-workspace.yaml example:

    verifyDepsBeforeRun: install
    optimisticRepeatInstall: true
    publicHoistPattern:
      - "*types*"
      - "!@types/react"
    
  • Projects using a file: dependency on a local tarball file (i.e. .tgz, .tar.gz, .tar) will see a performance improvement during installation. Previously, using a file: dependency on a tarball caused the lockfile resolution step to always run. The lockfile will now be considered up-to-date if the tarball is unchanged.

Patch Changes
  • pnpm self-update should not leave a directory with a broken pnpm installation if the installation fails.
  • fast-glob replace with tinyglobby to reduce the size of the pnpm CLI dependencies #​9169.
  • pnpm deploy should not remove fields from the deployed package's package.json file #​9215.
  • pnpm self-update should not read the pnpm settings from the package.json file in the current working directory.
  • Fix pnpm deploy creating a package.json without the imports and license field #​9193.
  • pnpm update -i should list only packages that have newer versions #​9206.
  • Fix a bug causing entries in the catalogs section of the pnpm-lock.yaml file to be removed when dedupe-peer-dependents=false on a filtered install. #​9112
Platinum Sponsors
Bit Bit Syntax
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap Stackblitz

v10.5.2: pnpm 10.5.2

Compare Source

Patch Changes
  • The pnpm config set command should change the global .npmrc file by default.
    This was a regression introduced by #​9151 and shipped in pnpm v10.5.0.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap

v10.5.1: pnpm 10.5.1

Compare Source

Patch Changes
  • Throw an error message if a pnpm-workspaces.yaml or pnpm-workspaces.yml file is found instead of a pnpm-workspace.yaml #​9170.
  • Fix the update of pnpm-workspace.yaml by the pnpm approve-builds command #​9168.
  • Normalize generated link paths in package.json #​9163
  • Specifying overrides in pnpm-workspace.yaml should work.
  • pnpm dlx should ignore settings from the package.json file in the current working directory #​9178.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap

v10.5.0: pnpm 10.5

Compare Source

Minor Changes
  • The pnpm.* settings from package.json can now be specified in the pnpm-workspace.yaml file instead #​9121.

    package.json:

    {
      "pnpm": {
        "onlyBuiltDependencies": ["esbuild", "fuse-native"]
      }
    }
    

    pnpm-workspace.yaml:

    onlyBuiltDependencies:
    - esbuild
    - fuse-native
    
  • Added support for automatically syncing files of injected workspace packages after pnpm run #​9081. Use the sync-injected-deps-after-scripts setting to specify which scripts build the workspace package. This tells pnpm when syncing is needed. The setting should be defined in a .npmrc file at the root of the workspace. Example:

    sync-injected-deps-after-scripts[]=compile
    
  • The packages field in pnpm-workspace.yaml became optional.

Patch Changes
  • pnpm link with no parameters should work as if --global is specified #​9151.
  • Allow scope registry CLI option without --config. prefix such as --@scope:registry=https://scope.example.com/npm #​9089.
  • pnpm link <path> should calculate relative path from the root of the workspace directory #​9132.
  • Fix a bug causing catalog snapshots to be removed from the pnpm-lock.yaml file when using --fix-lockfile and --filter. #​8639
  • Fix a bug causing catalog protocol dependencies to not re-resolve on a filtered install #​8638.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap

v10.4.1: pnpm 10.4.1

Compare Source

Patch Changes
  • Throws an error when the value provided by the --allow-build option overlaps with the pnpm.ignoredBuildDependencies list #​9105.
  • Print pnpm's version after the execution time at the end of the console output.
  • Print warning about ignored builds of dependencies on repeat install #​9106.
  • Setting init-package-manager should work.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap

v10.4.0

Compare Source

v10.3.0: pnpm 10.3

Compare Source

See breaking changes in v10

Minor Changes
  • Added a new setting called strict-dep-builds. When enabled, the installation will exit with a non-zero exit code if any dependencies have unreviewed build scripts (aka postinstall scripts) #​9071.
Patch Changes
  • Fix a false negative of verify-deps-before-run after pnpm install --production|--no-optional #​9019.
  • Print the warning about blocked installation scripts at the end of the installation output and make it more prominent.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap

v10.2.1: pnpm 10.2.1

Compare Source

Patch Changes
  • Don't read a package from side-effects cache if it isn't allowed to be built #​9042.
  • pnpm approve-builds should work, when executed from a subdirectory of a workspace #​9042.
  • pnpm deploy --legacy should work without injected dependencies.
  • Add information about how to deploy without "injected dependencies" to the "pnpm deploy" error message.
Platinum Sponsors
Bit Bit
Gold Sponsors
Discord u|screen
JetBrains Nx
CodeRabbit Route4Me
Workleap

v10.2.0: pnpm 10.2

Compare Source

See breaking changes in v10

Minor Changes
  • Packages executed via pnpm dlx and pnpm create are allowed to be built (run postinstall scripts) by default.

    If the packages executed by dlx or create have dependencies that have to be built, they should be listed via the --allow-build flag. For instance, if you want to run a package called bundle that has esbuild in dependencies and want to allow esbuild to run postinstall scripts, run:

    pnpm --allow-build=esbuild dlx bundle
    

    Related PR: #​9026.

Patch Changes
  • Quote args for scripts with shell-quote to support new lines (on POSIX only) #​8980.
  • Fix a bug in which pnpm deploy fails to read the correct projectId when the deploy source is the same as the workspace directory #​9001.
  • Proxy settings should be respected, when resolving Git-hosted dependencies #​6530.
  • Prevent overrides from adding invalid version ranges to peerDependencies by keeping the peerDependencies and overriding them with prod dependencies #​8978.
  • Sort the package names in the "pnpm.onlyBuiltDependencies" list saved by pnpm approve-builds.
Platinum Sponsors
Bit Bit Figma
Gold Sponsors
Discord Prisma
u|screen JetBrains
Nx CodeRabbit
Route4Me Workleap
Canva

v10.1.0: pnpm 10.1

Compare Source

See breaking changes in v10

Minor Changes
  • Added a new command for printing the list of dependencies with ignored build scripts: pnpm ignored-builds #​8963.
  • Added a new command for approving dependencies for running scripts during installation: pnpm approve-builds #​8963.
  • Added a new setting called optimistic-repeat-install. When enabled, a fast check will be performed before proceeding to installation. This way a repeat install or an install on a project with everything up-to-date becomes a lot faster. But some edge cases might arise, so we keep it disabled by default for now #​8977.
  • Added a new field "pnpm.ignoredBuiltDependencies" for explicitly listing packages that should not be built. When a package is in the list, pnpm will not print an info message about that package not being built #​8935.
Patch Changes
  • Verify that the package name is valid when executing the publish command.
  • When running pnpm install, the preprepare and postprepare scripts of the project should be executed #​8989.
  • Allow workspace: and catalog: to be part of wider version range in peerDependencies.
  • pnpm deploy should inherit the pnpm object from the root package.json #​8991.
  • Make sure that the deletion of a node_modules in a sub-project of a monorepo is detected as out-of-date #​8959.
  • Fix infinite loop caused by lifecycle scripts using pnpm to execute other scripts during pnpm install with verify-deps-before-run=install #​8954.
  • Replace strip-ansi with the built-in util.stripVTControlCharacters #​9009.
  • Do not print patched dependencies as ignored dependencies that require a build #​8952.
Platinum Sponsors
Bit Bit Figma
Gold Sponsors
Discord Prisma
u|screen JetBrains
Nx CodeRabbit
Route4Me Workleap
Canva

v10.0.0: pnpm 10

Compare Source

Major Changes
  • Lifecycle scripts of dependencies are not executed during installation by default! This is a breaking change aimed at increasing security. In order to allow lifecycle scripts of specific dependencies, they should be listed in the pnpm.onlyBuiltDependencies field of package.json #​8897. For example:

    {
      "pnpm": {
        "onlyBuiltDependencies": ["fsevents"]
      }
    }
    

    Read pnpm 10.0.0 Blocks Lifecycle Scripts by Default to learn about the motivation of the change.

    If you want the old pre v10 behaviour, so you want to allow all dependencies to run postinstall scripts, then add this to your package.json:

    {
      "pnpm": {
        "neverBuiltDependencies": []
      }
    }
    
  • pnpm link behavior updated:

    The pnpm link command now adds overrides to the root package.json.

    • In a workspace: The override is added to the root of the workspace, linking the dependency to all projects in the workspace.
    • Global linking: To link a package globally, run pnpm link from the package’s directory. Previously, you needed to use pnpm link -g.
      Related PR: #​8653
  • Secure hashing with SHA256:

    Various hashing algorithms have been updated to SHA256 for enhanced security and consistency:

    • Long paths inside node_modules/.pnpm are now hashed with SHA256.
    • Long peer dependency hashes in the lockfile now use SHA256 instead of MD5. (This affects very few users since these are only used for long keys.)
    • The hash stored in the packageExtensionsChecksum field of pnpm-lock.yaml is now SHA256.
    • The side effects cache keys now use SHA256.
    • The pnpmfile checksum in the lockfile now uses SHA256 (#​8530).
    • The patch file checksums in the lockfile now use SHA256.
  • Configuration updates:

    • manage-package-manager-versions: enabled by default. pnpm now manages its own version based on the packageManager field in package.json by default.

    • public-hoist-pattern: nothing is hoisted by default. Packages containing eslint or prettier in their name are no longer hoisted to the root of node_modules. Related Issue: #​8378

    • Upgraded @yarnpkg/extensions to v2.0.3. This may alter your lockfile.

    • virtual-store-dir-max-length: the default value on Windows has been reduced to 60 characters.

    • Reduced environment variables for scripts:
      During script execution, fewer npm_package_* environment variables are set. Only name, version, bin, engines, and config remain.
      Related Issue: #​8552

    • All dependencies are now installed even if NODE_ENV=production. Related Issue: #​8827

  • Changes to the global store:

    • Store version bumped to v10.

    • Some registries allow identical content to be published under different package names or versions. To accommodate this, index files in the store are now stored using both the content hash and package identifier.

      This approach ensures that we can:

      1. Validate that the integrity in the lockfile corresponds to the correct package, which might not be the case after a poorly resolved Git conflict.
      2. Allow the same content to be referenced by different packages or different versions of the same package.
        Related PR: #​8510
        Related Issue: #​8204
    • More efficient side effects indexing. The structure of index files in the store has changed. Side effects are now tracked more efficiently by listing only file differences rather than all files.
      Related PR: #​8636

    • A new index directory stores package content mappings. Previously, these files were in files.

  • Other breaking changes:

    • The # character is now escaped in directory names within node_modules/.pnpm.
      Related PR: #​8557
    • Running pnpm add --global pnpm or pnpm add --global @pnpm/exe now fails with an error message, directing you to use pnpm self-update instead.
      Related PR: #​8728
    • Dependencies added via a URL now record the final resolved URL in the lockfile, ensuring that any redirects are fully captured.
      Related Issue: #​8833
    • The pnpm deploy command now only works in workspaces that have inject-workspace-packages=true. This limitation is introduced to allow us to create a proper lockfile for the deployed project using the workspace lockfile.
    • Removed conversion from lockfile v6 to v9. If you need v6-to-v9 conversion, use pnpm CLI v9.
    • pnpm test now passes all parameters after the test keyword directly to the underlying script. This matches the behavior of pnpm run test. Previously you needed to use the -- prefix.
      Related PR: #​8619
  • node-gyp updated to version 11.

  • pnpm deploy now tries creating a dedicated lockfile from a shared lockfile for deployment. It will fallback to deployment without a lockfile if there is no shared lockfile or force-legacy-deploy is set to true.

Minor Changes
  • Added support for a new type of dependencies called "config dependencies". These dependencies are installed before all the other types of dependencies (before "dependencies", "devDependencies", "optionalDependencies").

    Config dependencies cannot have dependencies of their own or lifecycle scripts. They should be added using exact version and the integrity checksum. Example:

    {
      "pnpm": {
        "configDependencies": {
          "my-configs": "1.0.0+sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="
        }
      }
    }
    

    Related RFC: #​8.
    Related PR: #​8915.

  • New settings:

    • New verify-deps-before-run setting. This setting controls how pnpm checks node_modules before running scripts:

      • install: Automatically run pnpm install if node_modules is outdated.
      • warn: Print a warning if node_modules is outdated.
      • prompt: Prompt the user to confirm running pnpm install if node_modules is outdated.
      • error: Throw an error if node_modules is outdated.
      • false: Disable dependency checks.
        Related Issue: #​8585
    • New inject-workspace-packages setting enables hard-linking all local workspace dependencies instead of symlinking them. Previously, this could be achieved using dependenciesMeta[].injected, which remains supported.
      Related PR: #​8836

  • Faster repeat installs:

    On repeated installs, pnpm performs a quick check to ensure node_modules is up to date.
    Related PR: #​8838

  • pnpm add integrates with default workspace catalog:

    When adding a dependency, pnpm add checks the default workspace catalog. If the dependency and version requirement match the catalog, pnpm add uses the catalog: protocol. Without a specified version, it matches the catalog’s version. If it doesn’t match, it falls back to standard behavior.
    Related Issue: #​8640

  • pnpm dlx now resolves packages to their exact versions and uses these exact versions for cache keys. This ensures pnpm dlx always installs the latest requested packages.
    Related PR: #​8811

  • No node_modules validation on certain commands. Commands that should not modify node_modules (e.g., pnpm install --lockfile-only) no longer validate or purge node_modules.
    Related PR: #​8657

Platinum Sponsors
Bit Bit Figma
Gold Sponsors
Discord Prisma
u|screen JetBrains
Nx CodeRabbit
Route4Me Workleap
Canva

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about these updates again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [pnpm](https://pnpm.io) ([source](https://github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm)) | [`9.15.9` → `11.21.0`](https://renovatebot.com/diffs/npm/pnpm/9.15.9/11.21.0) | ![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.21.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/9.15.9/11.21.0?slim=true) | | [pnpm](https://pnpm.io) ([source](https://github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm)) | `8` → `11` | ![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.21.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/8.15.9/11.21.0?slim=true) | --- ### Release Notes <details> <summary>pnpm/pnpm (pnpm)</summary> ### [`v11.21.0`](https://github.com/pnpm/pnpm/releases/tag/v11.21.0): pnpm 11.21 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.20.0...v11.21.0) ##### Minor Changes - Added interactive group selection to `pnpm update --global --interactive`. - Running `pnpm setup`, `pnpm self-update`, or a command that modifies the global installation (such as `pnpm add --global`) through `sudo` now prints a warning. pnpm keeps global packages and configuration in the invoking user's home directory, so running these commands as root silently operates on the root user's home directory instead of yours. They will fail with `ERR_PNPM_SUDO_NOT_SUPPORTED` in pnpm v12. Read-only global commands (such as `pnpm bin --global`) are unaffected. ##### Patch Changes - Fixed pnpm failing to start under asynchronous Node.js module loaders when no `.pnpmfile.mjs` exists [pnpm/pnpm#11701](https://github.com/pnpm/pnpm/issues/11701). - Fixed `minimumReleaseAge` fallback for custom dist-tags so the selected version does not exceed the registry’s original tag target. - Removing a dependency from `package.json` and reinstalling no longer re-resolves the dependency graph. The importer's entry is dropped from `pnpm-lock.yaml`, anything it made unreachable is pruned, and a catalog entry that loses its last referent is removed — all without registry access. Installs still fall back to a full resolution when a package that stays resolves a peer dependency through the removed one, since that would change the surviving package's entry rather than only prune. - Changing a catalog entry to a different exact version no longer re-resolves the dependency graph. The package is replaced in `pnpm-lock.yaml` directly, reusing the same check the `pnpm.overrides` fast path applies: every locked dependency of the package must still satisfy the new version's manifest. Installs fall back to a full resolution when anything other than the catalog reaches the package — an importer that depends on it directly, or another package that depends on it — since the graph would then need both versions. - Fixed a CI regression where `github:owner/repo` dependencies (and other shorthand Git specifiers) would fail to install with `Permission denied (publickey)` on CI runners that lack SSH keys. The Git resolver no longer records an SSH URL unless the user explicitly wrote one (e.g. `git+ssh://` or `git@host:...`): - The repository visibility probe (an HTTP HEAD request) now retries transient failures such as `429 Too Many Requests`, so host throttling of CI runners is no longer mistaken for a private repository. - For non-SSH specifiers, anonymous HTTPS `git ls-remote` access is now tried before SSH, so a public repository whose visibility probe fails still resolves to a portable HTTPS URL instead of an SSH URL that only works where SSH keys are configured. - When every probe fails, the resolver falls back to HTTPS for shorthand and HTTPS-style specifiers, and only guesses SSH when the user explicitly provided an SSH URL. - A repository that could not be confirmed public is no longer resolved to the host's anonymous archive URL (e.g. `codeload.github.com`, which would fail to download for a private repository); it stays a regular `git` resolution so installs can use ambient Git credentials such as credential helpers and tokens. Note that a private repository that is reachable both over authenticated HTTPS and over SSH now resolves to its HTTPS URL, where previous versions recorded the SSH URL. Fixes [pnpm/pnpm#13276](https://github.com/pnpm/pnpm/issues/13276). <!-- cspell:ignore publickey --> - `ng build` and `nuxt build` now work under the global virtual store: pnpm's built-in compatibility extensions add the `tslib` dependency that `@angular/build` uses without declaring and the `unplugin` dependency that `@nuxt/vite-builder` v4 uses without declaring. - Fixed `link:` dependencies under `enableGlobalVirtualStore` so linked children are materialized and slots remain isolated by their resolved link targets. - An install that skips resolution because `pnpm-lock.yaml` is already up to date now reacts fully to packages the lockfile removed — for example after pulling a lockfile in which a dependency was deleted. The hoist layer is recomputed, so a package that became hoistable when a direct dependency was removed is hoisted, and `pendingBuilds` entries for removed packages are dropped instead of staying pending forever. - The held-back-update warning printed by `pnpm update` no longer fires when `minimumReleaseAge` is the actual reason a newer version was not picked. The warning's baseline now applies the same maturity cutoff as the pick itself, so it no longer wrongly attributes the hold-back to "your manifests and already installed dependencies" or recommends an override that would defeat the age gate. See [#&#8203;13071](https://github.com/pnpm/pnpm/issues/13071). - Checking whether `ignoredOptionalDependencies` is up to date no longer reorders the configured patterns. The check sorted them in place, which could move an `!` exclusion ahead of the pattern it excludes from and flip which optional dependencies were ignored. - Changing `autoInstallPeers`, `dedupePeers`, `peersSuffixMaxLength`, `excludeLinksFromLockfile`, or `injectWorkspacePackages` no longer re-resolves the dependency graph when the lockfile proves the setting cannot affect it: no package or project declares a peer dependency for the peer settings, and no project depends on a directory or on another workspace project for the link and injection settings. The new setting is recorded in `pnpm-lock.yaml` and the install proceeds from the existing resolution. Every other case still falls back to a full resolution. - Adding, editing, or removing an entry in `patchedDependencies` no longer re-resolves the dependency graph. Resolution never reads a patch — it only records the patch file's hash against the package it matches — so the install now rewrites the affected entries in `pnpm-lock.yaml` and materializes the patched package from the store instead. Installs still fall back to a full resolution when the patched package is reachable as a peer dependency, and when the new configuration would leave a patch unused while `allowUnusedPatches` is off, so `ERR_PNPM_UNUSED_PATCH` is still reported. - Resolving a private git repository no longer blocks on an interactive credential prompt: `git ls-remote` now fails fast with an authentication error when git has no credentials for the repository [#&#8203;13522](https://github.com/pnpm/pnpm/issues/13522). - Lockfile verification now honors offline mode by using cached registry metadata instead of reaching the registry. When the required metadata is not available locally, verification reports the same `ERR_PNPM_NO_OFFLINE_META` condition used by offline resolution. - POSIX shell shims now follow symbolic links before computing `basedir`, preventing execution failures when a shim is invoked via an external symlink on `PATH` [#&#8203;13405](https://github.com/pnpm/pnpm/issues/13405). - The automatic `packageManager` version switch works again on registries whose tarball URLs point at a different host than the registry itself (load-balanced feed proxies, Artifactory-style mirrors). Package-manager entries are now always recorded with integrity-only resolutions — the download URL is derived from the trusted bootstrap registry instead — and entries persisted in an invalid shape by an earlier pnpm are discarded and re-resolved instead of failing every command [#&#8203;13619](https://github.com/pnpm/pnpm/issues/13619). - Registries that serve no npm signature metadata (private mirrors and feed proxies commonly strip `dist.signatures`) no longer break the automatic `packageManager` version switch and `pnpm self-update` [#&#8203;13147](https://github.com/pnpm/pnpm/issues/13147). When the configured registry cannot provide a verifiable signature, pnpm now fetches the signature from `registry.npmjs.org` and verifies it against the same embedded npm keys over the installed integrity — which proves exactly the same thing. If no signature can be obtained from either source (for example, both are unreachable, or the registry publishes only a `shasum`), pnpm proceeds with a warning instead of failing, but only when the packages resolve through a registry configured in the user's own (non-project) configuration; the download stays pinned by the lockfile integrity, and a signature that exists but does not validate still fails the switch. - `pnpm fetch`, and any install run with `virtualStoreOnly`, no longer writes a `.pnp.cjs` loader under `nodeLinker: pnp`. These installs populate the virtual store without linking the project, so the loader would have claimed the project resolves out of a store it was never linked into. The importer links and `node_modules/.package-map.json` were already skipped; the PnP loader now follows the same rule. - Prevent pnpm from removing project files when `modulesDir` resolves to the project root. - Speed up installs after adding `ignoredOptionalDependencies` patterns by removing newly ignored optional dependencies and pruning packages that are no longer reachable without resolving the dependency graph again. - When a failed install re-copies a bin script from the store, rerunning `pnpm install` now reapplies the executable bit to the bin instead of leaving it non-executable [#&#8203;12742](https://github.com/pnpm/pnpm/issues/12742). - `pnpm root -g` and `pnpm bin -g` now print warnings to stderr instead of stdout, so their stdout stays a clean, machine-readable path. Previously, running either command with `--global` in a project that pins a package manager (e.g. via the `packageManager` field) printed a warning like `[WARN] Using --global skips the package manager check for this project` ahead of the path, breaking programs that capture the output as a path [#&#8203;13672](https://github.com/pnpm/pnpm/issues/13672). In pnpm 12, `pnpm root -g` and `pnpm prefix -g` are now supported (they previously failed with `ERR_PNPM_CLI_ROOT_GLOBAL_UNSUPPORTED` / `ERR_PNPM_CLI_PREFIX_GLOBAL_UNSUPPORTED`), and the reporter output of `dlx`, `create`, `config`, `sbom`, `with`, `store`, `prefix`, `root`, and `bin` goes to stderr, matching pnpm 11. - `pnpm setup` no longer makes Node.js print a `MODULE_TYPELESS_PACKAGE_JSON` warning about `dist/worker.js` on every command. The `package.json` it writes next to a standalone executable now declares `"type": "module"`. - `pnpm update` without saving no longer records a version that the manifest's range excludes. The kept range stays authoritative: a requested version outside it is skipped with a warning, and a requested range, a dist tag, or `--latest` resolves within it instead of past it. Previously each of these could write a lockfile entry that contradicted its own specifier, which the next `pnpm install --frozen-lockfile` rejected with `ERR_PNPM_OUTDATED_LOCKFILE` [#&#8203;12764](https://github.com/pnpm/pnpm/issues/12764). - `pnpm version -r --json` now outputs `[]` instead of human-readable text when no pending changes exist [`pnpm/pnpm#13217`](https://github.com/pnpm/pnpm/issues/13217). <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.20.0`](https://github.com/pnpm/pnpm/releases/tag/v11.20.0): pnpm 11.20 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.19.0...v11.20.0) ##### Minor Changes - **Security fix.** Affects projects using `namedRegistries` on pnpm 11.1.0–11.19.x. It is **semi-breaking** for those projects — see "If you use named registries" below. The lockfile recorded no marker for which registry a package came from. Packages were keyed by `name@version` alone, and entry lookup went through `refToRelative(ref, name)`, so a dependency you declared against one registry could be satisfied by an entry that was actually resolved from another. When two registries served the same name and version, both collapsed onto a single `packages:` entry and whichever resolved first decided the tarball every consumer got. That is a package-substitution risk: a package you expect from your private registry could be installed from a different registry that publishes the same name and version, and the lockfile recorded nothing that would let you tell. Packages resolved from a named registry are now recorded under registry-qualified keys (`<name>@<registryName>:<version>`, e.g. `foo@work:1.0.0`), so each registry gets its own entry and the lockfile pins which one a dependency came from. The lockfile format version is unchanged. Registry-qualified keys appear only for packages resolved from a named registry, so a project that does not use `namedRegistries` sees no difference, and older pnpm versions keep reading the file. ##### If you use named registries Your next non-frozen install re-keys those entries, which shows up as a lockfile diff. Commit it — that diff is the fix being applied. Review it: an entry that moves to a registry you did not expect is worth investigating. Everyone working on the project should be on this version or newer before you do. An older pnpm reads the re-keyed lockfile fine — frozen installs are unaffected — but it does not produce registry-qualified keys itself, so any install that updates the lockfile writes those entries back to the old shape, and the next install on a current pnpm re-qualifies them. The result is a lockfile that flips back and forth, and while it is in the old shape the project is exposed again. Because the lockfile format version is deliberately unchanged, pnpm cannot detect this and warn you about it. There is no setting to keep the old behavior: the old shape is the vulnerability. Tarball URLs that follow the standard registry layout are no longer written to the lockfile for named-registry packages; they are recomputed from the `namedRegistries` setting on demand. To use named registries, map your aliases in `pnpm-workspace.yaml`: ```yaml namedRegistries: work: https://npm.enterprise.example.com/ ``` ##### New built-in `npmjs:` alias `npmjs:` now resolves to `https://registry.npmjs.org/` with no configuration, alongside the existing `gh:` alias for GitHub Packages. It pins a dependency to the public registry even when `registry` points elsewhere, such as an internal proxy: ```json { "dependencies": { "left-pad": "npmjs:^1.3.0" } } ``` `npm:` cannot do this — it is the alias protocol (`npm:<name>@<range>`) and resolves through whatever `registry` points at. **If you mirror or proxy npmjs, point the alias at your mirror:** ```yaml namedRegistries: npmjs: https://npm.internal.example.com/ ``` Built-in registry URLs are also the prefixes a lockfile's recorded tarball URL is matched against when pnpm verifies a package. Without the override, an entry whose tarball URL is on `registry.npmjs.org` is verified against the public registry rather than your mirror. This only affects lockfiles that record such URLs — a canonical URL for your configured registry is omitted from the lockfile and unaffected — and only when a tarball-URL, `minimumReleaseAge`, or `trustPolicy` check runs. Overriding the alias is the same escape hatch GHES users already have for `gh`. Every alias the lockfile references must stay in `namedRegistries`: reading an entry whose alias is gone fails with `ERR_PNPM_MISSING_NAMED_REGISTRY` rather than silently falling back to the default registry, since that would fetch a different package. Renaming an alias re-resolves the packages that used it. Named registry aliases that shadow a reserved dependency specifier prefix (`file`, `link`, `workspace`, `runtime`, `npm`, `jsr`, ...) are now rejected with `ERR_PNPM_RESERVED_NAMED_REGISTRY_NAME` instead of being silently shadowed by the corresponding resolver. `pnpm licenses` and `pnpm sbom` now keep the two artifacts apart as well: license records carry the registry alias, and SBOM components carry the purl `repository_url` qualifier. ##### Patch Changes - An empty `http-proxy`, `https-proxy`, `proxy`, or `no-proxy` value — from the `.npmrc`, `pnpm-workspace.yaml`, the CLI, or the `HTTP_PROXY` / `HTTPS_PROXY` / `PROXY` / `NO_PROXY` environment variables — no longer fails the install with `ERR_PNPM_INVALID_PROXY`. Empty settings read as unset, so a shell exporting `HTTP_PROXY=` disables the proxy, and an empty `proxy=` in the `.npmrc` no longer suppresses `HTTPS_PROXY` [#&#8203;13533](https://github.com/pnpm/pnpm/issues/13533). `proxy=false` in the `.npmrc` or `proxy: false` in `pnpm-workspace.yaml` now turns proxying off instead of being read as a proxy host named `false`. `false` and `null` on `https-proxy` / `http-proxy` / `no-proxy` read as unset, and on the command line they are ordinary host names, since a flag carries its value verbatim. - The env lockfile no longer pins `@pnpm/exe` alongside `pnpm` when the wanted pnpm version is 12 or newer. From v12 the unscoped `pnpm` package is itself the native executable, so `@pnpm/exe` is not published for it and resolving it would fail. The engine identity check now verifies the native binary through whichever package ships it. - `lexCompare` and `nerfDart` are now published as `@pnpm/text.ordinal-comparator` and `@pnpm/config.registry-auth-key`. Use these instead of `@pnpm/util.lex-comparator` and `@pnpm/config.nerf-dart`. - Fixed the order in which pnpm matches a lockfile's recorded tarball URL against known registry URLs. Two registry URLs of equal length were previously ordered arbitrarily, so which one a tarball URL matched could differ between runs. - Dependency resolution is faster: package metadata is now filtered once per packument instead of once per dependency edge when `minimumReleaseAge` is active, and parsed semver versions and ranges are reused instead of re-parsed on every comparison. - Security: `pnpm rebuild` now refuses a lockfile whose `packages` key carries a path traversal in the package name (e.g. `../../../escaped@1.0.0`), instead of running that package's lifecycle scripts and linking its bins in a directory outside the virtual store. Such a name is rejected with `ERR_PNPM_INVALID_DEPENDENCY_NAME`. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.19.0`](https://github.com/pnpm/pnpm/releases/tag/v11.19.0): pnpm 11.19 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.18.0...v11.19.0) ##### Minor Changes - `pnpm login` no longer requires an interactive terminal when the registry supports web-based login: without a TTY it prints the authentication URL (skipping the QR code and the "Press ENTER to open the URL in your browser" prompt) and polls the registry until the browser approval completes. Only the classic username/password login still fails with `ERR_PNPM_LOGIN_NON_INTERACTIVE` in a non-interactive terminal. - The `save-prefix` setting now accepts `=`: newly added dependencies are saved with an explicit `=` operator (`=1.2.3`) instead of the setting being silently treated as the default `^`. ##### Patch Changes - `allowBuilds` entries can now approve git-hosted packages that pnpm downloads as a tarball, such as `github:` dependencies (which are fetched from `codeload.github.com` rather than cloned), by their repository URL without the resolved commit hash. This matches the hashless `git+` matching already supported for cloned git dependencies. For example: ```yaml allowBuilds: "foo@git+https://github.com/org/foo.git": true ``` This approves the package whether pnpm clones it or downloads a tarball, so the entry no longer has to be updated every time the pinned commit changes. GitLab and Bitbucket tarball downloads are matched the same way. Approving or denying a specific resolved commit by its full tarball dep path continues to work. - `pnpm outdated --include-github-actions` no longer blocks on an interactive git credential prompt when a workflow uses a private action repo. - Prevented `minimumReleaseAge` from replacing `latest` with a SemVer-greater version than the registry tag target [#&#8203;13034](https://github.com/pnpm/pnpm/issues/13034). - Fixed empty `bundledDependencies` and `bundleDependencies` arrays causing nondeterministic lockfile changes. See [#&#8203;13123](https://github.com/pnpm/pnpm/issues/13123). - The install summary no longer prints `(X is available)` when the registry's `dist-tags.latest` is still held back by the active `minimumReleaseAge` policy. The hint only ever names the actual latest tag, so an immature latest suppresses the hint instead of advertising the version pnpm just refused to install [#&#8203;11698](https://github.com/pnpm/pnpm/issues/11698). - `pnpm update` keeps the explicit `=` operator of an exact version pin: a dependency saved as `=3.5.1` now updates to `=3.5.2` instead of the bare `3.5.2`. See [#&#8203;13168](https://github.com/pnpm/pnpm/issues/13168). - Preserve a workspace dependency's `link:` entry when a run does not target it — e.g. `pnpm update <other-pkg>` (with or without `--recursive`), or a plain install after a root/catalog dependency change — with `injectWorkspacePackages`, instead of spuriously rewriting it to a peer-suffixed `file:` protocol. See [#&#8203;10433](https://github.com/pnpm/pnpm/issues/10433). - Workspace dependencies declared with a relative path (e.g. `"foo": "workspace:../foo"`) are no longer silently dropped from the workspace projects graph, so `--filter` selection and the topological order of recursive commands take them into account. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.18.0`](https://github.com/pnpm/pnpm/releases/tag/v11.18.0): pnpm 11.18 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.17.0...v11.18.0) ##### Minor Changes - Fixed an installed optional dependency being left without one of its own required dependencies. When a package reached through `optionalDependencies` is installable on the current system but one of its regular `dependencies` is not, a lockfile-based install skipped that dependency and installed the parent anyway, so importing the parent failed with `MODULE_NOT_FOUND`. The dependency is now installed, and an install-check warning reports the incompatibility. A dependency is still only skipped when every path to it is optional, or when the package that pulls it in was itself skipped [#&#8203;13286](https://github.com/pnpm/pnpm/issues/13286). - `pnpm setup` now appends `PNPM_HOME` and the global bin directory to the GitHub Actions environment files (`GITHUB_ENV` and `GITHUB_PATH`), so later steps in the same job can run `pnpm add --global` and other global commands [#&#8203;9191](https://github.com/pnpm/pnpm/issues/9191). - Added support for `publishConfig.name`, which publishes a package under a different name than the one its manifest carries in the workspace. It is for a project whose published name is already taken by a sibling project, which otherwise has to be renamed by a build step just before publishing. Only the published artifact is renamed — dependents, `pnpm-lock.yaml`, and release tooling keep addressing the project by its manifest name — and the new name reaches the packed manifest, the tarball filename, and everything that addresses the package at the registry: the already-published check of `pnpm publish -r`, its registry selection, and the release-planning probes of `pnpm change status` and `pnpm version -r` [#&#8203;13345](https://github.com/pnpm/pnpm/issues/13345). - `pnpm self-update` no longer takes any instruction from the project it is run in: - pnpm is fetched through the same trusted registry and auth configuration used when switching pnpm versions, so a project `.npmrc` or `pnpm-workspace.yaml` can no longer redirect the download or attach credentials to it, and the project's default `.pnpmfile.(c|m)js` is no longer loaded. Pnpmfiles from trusted sources (the `pnpmfile` setting, the global pnpmfile, config dependencies) still apply. - The `minimumReleaseAge` settings in `pnpm-workspace.yaml` no longer affect `self-update`. They still govern the project's own dependencies; for `self-update` the cooldown now comes from the built-in default, your global config, a `PNPM_CONFIG_*` environment variable, or a command-line flag. This fixes `self-update` failing inside a workspace that raises the cutoff while succeeding everywhere else, and stops a repository from either waiving the cooldown or keeping you on an outdated pnpm by raising it. - The same applies to the `trustPolicy` settings and to `ci`: a project can no longer weaken the trust check that guards the pnpm download, nor re-enable the confirmation prompt that a CI run suppresses. When `self-update` refuses a version that is younger than the cutoff, an interactive run now offers to update anyway; non-interactive runs still fail. CI never prompts, even on a runner that attaches a TTY. ##### Patch Changes - Fixed `pnpm licenses list` to report every version when the same package is installed under multiple aliases [pnpm/pnpm#13438](https://github.com/pnpm/pnpm/issues/13438). - Sort `pnpm dedupe --check` snapshot changes for stable output across pnpm implementations. - Strip Unicode formatting characters from registry- and manifest-derived terminal output. - Speed up installs after compatible catalog or direct dependency range changes by retaining the locked version without resolving the dependency graph again. - Speed up installs after safe override changes by reusing unambiguous compatible dependency resolutions, pruning obsolete dependencies, applying independent replacements and removals together, and handling parent-scoped `"-"` overrides without full lockfile resolution. - Installing a local `file:` directory dependency with the global virtual store enabled no longer fails with `TypeError: Cannot read properties of undefined (reading 'split')` [#&#8203;13335](https://github.com/pnpm/pnpm/issues/13335). Local directory dependencies — `file:` directories and injected workspace packages — now get a global-virtual-store slot of their own per project. They used to share one slot across every project that depended on a directory of the same name, so a project could end up linked to another project's copy of the dependency. - The `Workspace` column of `pnpm update --interactive` now falls back to the project's path when its `name` is only whitespace, as it already did for a missing or empty one — all three render an equally blank label otherwise. - Checking GitHub Actions dependencies for updates is now opt-in for every command. Neither `pnpm outdated` nor `pnpm update` reads the workflow files unless `--include-github-actions` is passed or `update.githubActions` is set to `true` in `pnpm-workspace.yaml`. Reading them runs `git ls-remote` against every referenced repository, which fails in environments where GitHub is not reachable the way pnpm assumes (a GitHub Enterprise Server, a custom certificate authority, or an offline network) [#&#8203;13254](https://github.com/pnpm/pnpm/issues/13254). `pnpm outdated` accepts the `--include-github-actions` option too. - `pnpm update --interactive` now measures its table in terminal columns rather than in characters. A package name, workspace name, or version containing wide characters (CJK, most emoji) no longer knocks its row's columns out of line with the rest of the group, and a wide character in a version no longer aborts the command with `Subject parameter value width cannot be greater than the container width` [#&#8203;13357](https://github.com/pnpm/pnpm/issues/13357). - The `Workspace` column of `pnpm update --interactive` is more informative in two cases. A dependency outdated at the same version in several workspace projects is offered as one choice, since selecting it updates every project — that choice now names all of them instead of only the first. And a workspace project without a `name` is now labelled with its path rather than left blank, so several unnamed projects can be told apart. - An auto-installed *optional* peer is no longer hoisted at a version the workspace root's own dependency on that package excludes. `resolvePeersFromWorkspaceRoot` already made the workspace root's specifier decide which version a missing *required* peer is installed at; the optional-peer picker ignored it and always took the highest version present anywhere in the graph. In a workspace whose root pins `postcss: 8.5.10`, an importer that depends on `webpack` and declares no `postcss` of its own got `postcss@8.5.22` hoisted for `terser-webpack-plugin`'s optional `postcss` peer, leaving two `postcss@8.5.x` instances in the graph [#&#8203;13320](https://github.com/pnpm/pnpm/issues/13320). - `overrides` now also govern peers that pnpm auto-installs. Previously an override only rewrote dependencies declared in a manifest, so a peer nobody declares — installed because `autoInstallPeers` is on — resolved against its declared peer range and could bring in a second copy of the very package the override pinned. For example, with `overrides: { react: npm:react@19.2.0 }` and a lone `lucide-react` dependency, pnpm installed `react@18.3.1`; it now installs the pinned `react@19.2.0` [#&#8203;13320](https://github.com/pnpm/pnpm/issues/13320). - Under `resolvePeersFromWorkspaceRoot`, a workspace root dependency declared with `link:` or `file:` (or the path form of `workspace:`, such as `workspace:../pkg`) now satisfies another project's missing peer dependency at the linked package's own version, instead of being hoisted as a path. Those specifiers are relative to the project that declares them, so the same specifier reached a different directory — or none — from the project the peer was hoisted into, leaving a broken link. The root now has the same authority over the peer as it has when it declares the package with a version range [#&#8203;13373](https://github.com/pnpm/pnpm/issues/13373). - Installs through a pnpr server now apply the project's whole verification policy. `minimumReleaseAgeExclude`, `minimumReleaseAgeIgnoreMissingTime`, `trustPolicy`, `trustPolicyExclude`, `trustPolicyIgnoreAfter`, and `trustLockfile` were ignored, so excluded packages were still held back and a lockfile containing them could be rejected. `trustPolicy: no-downgrade` no longer fails with `TRUST_POLICY_INCOMPATIBLE_WITH_PNPR` when a pnpr server is configured. `--frozen-lockfile` and `--no-prefer-frozen-lockfile` are now honored on the pnpr path, instead of resolving and rewriting the lockfile anyway. Since `frozenLockfile` defaults to `true` on CI, a CI install through a pnpr server now fails on an out-of-date lockfile rather than updating it. - Workspace installs through a pnpr server no longer crash with `Cannot read properties of undefined (reading 'filter')` after linking, when `minimumReleaseAge` is active [#&#8203;13275](https://github.com/pnpm/pnpm/issues/13275). - Fixed `pnpm dedupe` updating valid catalog resolutions when another matching version exists in the lockfile. - `pnpm -r run "/pattern/" --no-bail` no longer exits zero when one of a project's matched scripts fails and a later one passes. The run summary carries a single status per project, and the passing script overwrote the recorded failure. - Restored the store block a first install prints, naming how packages were materialized and where the stores live [#&#8203;13315](https://github.com/pnpm/pnpm/issues/13315): ```text Packages are hard linked from the content-addressable store to the virtual store. Content-addressable store is at: ~/.local/share/pnpm/store/v11 Virtual store is at: node_modules/.pnpm ``` - The root project's `pnpm:devPreinstall` script now runs before resolution and linking, as it does in pnpm 11. It is skipped under `--ignore-scripts`, `--lockfile-only` and `--dry-run`, by `pnpm fetch` and `pnpm rebuild`, and by a repeat install that is already up to date. Workspaces that use the hook to prepare state the install depends on — such as [next.js](https://github.com/vercel/next.js), which generates a placeholder `next` bin with it — were left with dependents linked against files that were never created [#&#8203;13313](https://github.com/pnpm/pnpm/issues/13313). - Prevented `pnpm dedupe --check` from removing an incompatible `node_modules` directory. - `pnpm update --workspace` no longer links dependencies the user never named: - Running it with `updateConfig.ignoreDependencies` configured no longer fails with `ERR_PNPM_WORKSPACE_PACKAGE_NOT_FOUND` for a dependency that is only published to the registry. Such dependencies keep their specifiers, as they already did when no dependencies were ignored. - Passing package selectors that match no direct dependency no longer falls back to linking every workspace 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.17.0`](https://github.com/pnpm/pnpm/releases/tag/v11.17.0): pnpm 11.17 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.16.0...v11.17.0) ##### Minor Changes - Added a new setting, `update.githubActionsServer`, for specifying the base URL of the GitHub server that hosts the repositories of the GitHub Actions referenced by the workflow files (for example, a GitHub Enterprise Server). When the setting is not defined, the URL is read from the `GITHUB_SERVER_URL` environment variable, falling back to `https://github.com`. The URL must use the `https://` or `http://` protocol [#&#8203;13220](https://github.com/pnpm/pnpm/issues/13220). `pnpm outdated` and `pnpm update` no longer fail when the refs of a GitHub Action's repository cannot be read (for example, when the action's repository is private or hosted on a different GitHub server). Such actions are now skipped with a warning. Setting `update.githubActions` to `false` now makes `pnpm outdated` and the interactive `pnpm update` skip GitHub Actions dependencies. ##### Patch Changes - The token poll for web-based authentication no longer reads the body of non-OK or still-pending (HTTP 202) responses, and caps the token response body it does read at 64 KiB, so a malicious or compromised registry cannot exhaust memory through the poll [pnpm/pnpm#12721](https://github.com/pnpm/pnpm/issues/12721). - Fixed `catalog:` references in dependencies and overrides failing to resolve when installing through a pnpr server, which errored with "No catalog entry '<name>' was found for catalog 'default'." even though the catalog entry existed. Also fixed a crash on Windows when installing a nested workspace member (e.g. `packages/foo`) through a pnpr server [#&#8203;13232](https://github.com/pnpm/pnpm/issues/13232). - Republished every package: the tarballs published by the v11.13.1 through v11.16.0 releases were missing most of their compiled files due to a packing bug [#&#8203;13164](https://github.com/pnpm/pnpm/issues/13164). - Revert script ordering change for `pnpm run --sequential /regex/` - Support the `from-git` argument in the `pnpm version` command. - When the authentication URL cannot be rendered as a QR code (for example when it exceeds the maximum QR data capacity), web-based login now displays the URL alone with a warning instead of aborting authentication [pnpm/pnpm#12721](https://github.com/pnpm/pnpm/issues/12721). <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.16.0`](https://github.com/pnpm/pnpm/releases/tag/v11.16.0): pnpm 11.16 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.15.1...v11.16.0) ##### Minor Changes - The first release of a package now publishes the version written in its manifest verbatim, instead of bumping off it. `pnpm version -r` and `pnpm change status` check the registry for each release's current version; when that version is not yet published, the package debuts at it and its pending changesets apply only from the next release. A newly added package seeded at `1100.0.0` with a `minor` changeset is therefore published as `1100.0.0` rather than skipping straight to `1100.1.0`. - Added a `--changeset` flag to `pnpm update`. Set `update.changeset` to `true` in `pnpm-workspace.yaml` to enable this behavior by default, and use `--no-changeset` to override the setting for one update. After the update completes, pnpm writes a `.changeset/pnpm-update-<suffix>.md` file declaring a patch bump for every workspace package whose `dependencies` or `optionalDependencies` were changed by the update and a major bump when `peerDependencies` changed, including packages that consume an updated catalog entry via the `catalog:` protocol. Private packages, packages without a name, and packages listed in the `ignore` array of `.changeset/config.json` are skipped. If `.changeset/config.json` does not exist, a warning is printed and no changeset is generated. - Added GitHub Actions dependencies to `pnpm outdated` and interactive `pnpm update`. Non-interactive updates can include them with `--include-github-actions` or by setting `update.githubActions` to `true` in `pnpm-workspace.yaml`. Updated actions are pinned to exact commit hashes with their release tags preserved in comments. - Added `update` and `audit` settings sections to `pnpm-workspace.yaml`, superseding the awkwardly named `updateConfig`, `auditConfig`, and top-level `auditLevel` settings: ```yaml update: ignoreDeps: # was updateConfig.ignoreDependencies - webpack - "@babel/*" audit: level: high # was auditLevel ignore: # was auditConfig.ignoreGhsas - GHSA-xxxx-yyyy-zzzz ``` `update.ignoreDeps` lists dependency name patterns that `pnpm update` and `pnpm outdated` should skip. `audit.level` and `audit.ignore` tune `pnpm audit`. The deprecated `updateConfig`, `auditConfig`, and `auditLevel` settings keep working until the next major version. When both a new section value and its deprecated counterpart are set, the new section takes precedence and a warning is printed. Both the TypeScript CLI and the Rust config surface (pacquet) recognize the new sections. ##### Patch Changes - Fixed `pnpm add --save-exact`/`--save-prefix` and `pnpm update` writing a package's version with the `peerDependencies` range's prefix (e.g. `^19.2.7` instead of the requested `19.2.7`) whenever the same package also appeared in `peerDependencies`. A real `dependencies`/`devDependencies`/`optionalDependencies` entry now takes precedence over a same-named `peerDependencies` entry when computing the current specifiers [#&#8203;13108](https://github.com/pnpm/pnpm/issues/13108). <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.15.1`](https://github.com/pnpm/pnpm/releases/tag/v11.15.1): pnpm 11.15.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.15.0...v11.15.1) ##### Patch Changes - `pnpm install` now detects a `supportedArchitectures` change and re-evaluates previously skipped platform-specific optional dependencies, instead of reporting the project as up to date and leaving the packages for the old architecture set in place. - `pnpm setup` now removes leftover v10-layout shims at the top of `PNPM_HOME`, so `pnpm self-update` no longer warns about a v10 installation layout after PATH has been migrated to the v11 `PNPM_HOME/bin` layout. Applies to both the TypeScript CLI and pacquet. In the TypeScript CLI, `self-update` also no longer treats a dangling legacy shim (one whose install target was garbage-collected) as a real v10 layout, so the warning can no longer fire on dead shim files. Closes [#&#8203;12496](https://github.com/pnpm/pnpm/issues/12496). - Completed pnpm runtime installation parity for Node.js, Deno, and Bun, including runtime failure policy, target architecture selection, and dependency runtime engines. Runtime failure overrides now preserve explicit runtime dependencies without matching engine entries. - Fixed `pnpm install` running out of memory while resolving large dependency graphs [#&#8203;8441](https://github.com/pnpm/pnpm/issues/8441). The resolver kept full registry documents — per-version readmes, scripts, descriptions, and other install-irrelevant bulk — in memory for every package fetched with full metadata (optional dependencies, and packages re-fetched for `minimumReleaseAge`'s publish timestamps). Every retained document is now condensed down to the field set installation actually reads, which reduces peak resolution memory by several times on workspaces with more than a thousand packages. - When a dependency's build script fails under `enableGlobalVirtualStore`, the global virtual store directory it was being built in is now removed for scoped packages too. Previously the cleanup resolved one directory level short of the hash directory for a scoped name, leaving a half-built directory behind that later installs would reuse. - Fixed `pnpm login`, `pnpm adduser`, and `pnpm logout` against a registry hosted under a URL subpath (e.g. `https://example.com/npm/registry`) when the configured URL has no trailing slash. Such URLs were left unnormalized, so the last path segment was dropped when building the login and token endpoints and the auth token was stored under a truncated key. Registry URLs with a path now always get a trailing slash appended during normalization, matching how root-level registry URLs are handled. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.15.0`](https://github.com/pnpm/pnpm/releases/tag/v11.15.0): pnpm 11.15 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.14.0...v11.15.0) ##### Minor Changes - Optional peer dependencies declared only via `peerDependenciesMeta` (for example `debug`'s `supports-color` peer) are now resolved from a satisfying version already present in the dependency graph, the same way explicitly declared optional peer dependencies are. Previously such peers were only resolved this way when the package's metadata was read back from the lockfile, so an unrelated dependency change could rewrite peer resolutions across the whole lockfile. ##### Patch Changes - Updated `adm-zip` to prevent crafted ZIP archives from causing excessive memory allocation. - `pnpm version -r` no longer writes a versioning-ledger entry with no consumed intents as a bare `intents:` key, which the next run failed to read with `ERR_PNPM_INVALID_VERSIONING_LEDGER`. Empty intent lists are now written as `intents: []`, and the ledger reader accepts the bare form left by earlier releases. - Fixed pnpr workspace resolution to preserve project names and versions for `workspace:` dependencies. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.14.0`](https://github.com/pnpm/pnpm/releases/tag/v11.14.0): pnpm 11.14 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.13.1...v11.14.0) ##### Minor Changes - `peerDependencies` now accept dependency specifiers that carry a scheme — a named-registry spec (`<registry>:<version>`), an `npm:` alias, or a `file:`/git/URL spec — instead of rejecting them with `ERR_PNPM_INVALID_PEER_DEPENDENCY_SPECIFICATION` [#&#8203;13095](https://github.com/pnpm/pnpm/issues/13095). Such a peer is matched against the semver range carried by the specifier (`work:5.x.x` is checked as `5.x.x`, `npm:bar@^5` as `^5`), or against `*` when it carries no version, while the original specifier still selects the package to auto-install. Bare `name@version` values, which are almost always a mistake, are still rejected. - Added `pnpm doctor`, which diagnoses the pnpm installation and the environment it runs in: the versions and install method, whether the global bin directory is on `PATH`, whether the store and cache are writable, which link strategies (reflink, hardlink, symlink) the store's filesystem supports, registry connectivity, and an offline `file:` install that exercises the resolve/store/link path end to end. Each check reports how to fix what it finds, and the command exits non-zero when any check fails. Use `--offline` to skip the checks that need network access, `--json` for machine-readable output, and `--benchmark` to time the filesystem and install checks. - Added support for executing multiple scripts matching a RegExp passed to `pnpm run` (e.g., `pnpm run "/^build:.*/"`), running matched scripts in deterministic lexicographical order. Restored the `--sequential` (`-s`) CLI option for `pnpm run`, which forces `workspaceConcurrency` to 1 so that matched scripts run sequentially one by one across and within packages. ##### Patch Changes - Fixed `pnpm install` failing with `ERR_PNPM_LOCKFILE_IS_SYMLINK` when `pnpm-lock.yaml` is a symlink, as build sandboxes such as Bazel and Nix stage it [#&#8203;13073](https://github.com/pnpm/pnpm/issues/13073). Reading a lockfile through a symlink is allowed again, and an install that leaves the lockfile unchanged no longer rewrites it, so `--frozen-lockfile` no longer needs to write at all. Writing a *changed* lockfile through a symlink is still refused, as that would redirect the write onto the symlink's target. - Fixed frozen installs incorrectly treating equivalent Git dependency specifiers as a stale lockfile. See [#&#8203;13039](https://github.com/pnpm/pnpm/issues/13039). - `pnpm owner ls` now reports authentication and authorization failures (401/403) as dedicated errors that include the registry's response body, matching `pnpm owner add`/`rm`, instead of a generic `Failed to fetch owners` message. - Recover from a metadata cache entry that disappears (concurrent cache cleanup, antivirus) after the registry has already answered the conditional request with `304 Not Modified`. The metadata is re-requested once without cache validators instead of failing the install with `ERR_PNPM_CACHE_MISSING_AFTER_304`. - A project pinned to a broken pnpm release via `packageManager` or `devEngines.packageManager` now reports which release is broken and what to do about it, instead of failing inside the installer. `pnpm self-update` already refused these releases; the version switch does too. - Prevent broken-lockfile errors from including snippets of the lockfile's contents. - `pnpm self-update` now checks that the version it installed can run before making it the active pnpm. A release that installs but cannot execute is discarded with an error instead of replacing a working installation. - Fixed an out-of-memory regression when workspace projects concurrently resolve a package with large registry metadata [pnpm/pnpm#13077](https://github.com/pnpm/pnpm/issues/13077). - Fixed `pnpm update` rewriting exact version pins that use the `=` operator (for example `=3.5.1`) to a caret range (`^3.5.1`). Exact pins are now preserved and written back as the bare version. See [#&#8203;12745](https://github.com/pnpm/pnpm/issues/12745). <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.13.1`](https://github.com/pnpm/pnpm/releases/tag/v11.13.1): pnpm 11.13.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.13.0...v11.13.1) ##### Patch Changes - Fixed `pnpm pack` applying workspace-root ignore rules when a workspace package has its own `.npmignore` file. - Keep the interactive `minimumReleaseAge` approval prompt visible during `pnpm install`. The progress reporter now pauses its redraws while a prompt is waiting for input instead of overwriting it, so the install no longer hangs on a question the user cannot see [#&#8203;13019](https://github.com/pnpm/pnpm/issues/13019). - Fixed `pnpm self-update` failing to link native platform binaries stored in sibling global virtual store slots. ### [`v11.13.0`](https://github.com/pnpm/pnpm/releases/tag/v11.13.0): pnpm 11.13 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.12.0...v11.13.0) ##### Minor Changes - Added `versioning.epics` to `pnpm-workspace.yaml`. An epic ties a group of member packages to a lead package, constraining every member's major version to a band derived from the lead's major: while the lead is on major `M`, members live in `M*100 … M*100+99`. Members move independently inside the band (patch, minor, and a `major` intent that stays in-band); a bump that would carry a member past the band ceiling is rejected until the lead advances its own major. When a release plan takes the lead to a new stable major, every member re-bases to the band floor in the same plan. Membership is matched with pnpm's package selectors — name globs, `./`-prefixed directory globs, and `!`-prefixed negations. - Added the `team` command for managing organization teams and team memberships on the registry, with create, destroy, add, rm, and ls subcommands and support for --otp, --parseable, and --json flags. - Added native workspace release management [#&#8203;12952](https://github.com/pnpm/pnpm/issues/12952): the new `pnpm change` command records change intents as changesets-compatible `.changeset/*.md` files (`pnpm change status` shows the pending release plan), and the bare `pnpm version -r` consumes them — bumping versions across the workspace with dependent propagation through `workspace:` ranges, fixed groups, a `maxBump` cap, `--filter` narrowing, and `--dry-run` — writing changelogs, and recording consumed intents in a committed ledger that keeps cherry-picks and merge-backs between release branches safe. Packages can be moved onto per-package release lanes with the new `pnpm lane <name> --filter <pkg>` command and back with `pnpm lane main --filter <pkg>` (`pnpm lane` shows the membership), releasing `X.Y.Z-lane.N` prereleases from the same runs that release stable versions of the packages on the main lane. Configuration lives under the new `versioning` key of `pnpm-workspace.yaml` (`fixed`, `ignore`, `maxBump`, `lanes`, `changelog`). When two workspace projects publish the same name, intent files, `versioning.lanes`, and `versioning.fixed`/`ignore` may reference a project by its workspace-relative directory path (e.g. `"./pnpm/npm/pnpm"`) — the one additive extension to the changesets format, applied automatically by `pnpm change`. Release changelogs default to `registry` storage (`versioning.changelog.storage`): no `CHANGELOG.md` is committed. Each release's section is composed at publish time and packed into the published tarball on top of the previously published version's changelog, and the consumed change intents are garbage-collected by a later `pnpm version -r` only once the registry confirms the version is published with its section. Set `versioning.changelog.storage: repository` to keep committed `CHANGELOG.md` files instead. - Added a new override selector form with an empty range — `"pkg@": "<version>"` — called a convergence override. It rewrites a dependency edge only when its exact version satisfies the edge's declared range, so compatible consumers converge on one version while incompatible consumers keep their own resolution — now and for any dependent added in the future [#&#8203;12794](https://github.com/pnpm/pnpm/issues/12794). ```yaml overrides: "form-data@": 4.0.6 ``` The value must be an exact version. When a full resolution detects that every declared range also admits a newer version, pnpm warns that the override is stale and names the version to converge on. Previously an empty range in an override selector was undocumented and behaved like a bare (unscoped) override. ##### Patch Changes - A `tokenHelper` set in the global pnpm `auth.ini` is no longer rejected as project-level configuration. The guard that blocks `tokenHelper` from a project `.npmrc` only treated `~/.npmrc` as a trusted source, so a helper written to `auth.ini` (for example by `pnpm config set`) failed on every command and could not even be removed with `pnpm config delete`. A `tokenHelper` in a workspace or project `.npmrc` is still rejected. - `pnpm cache delete` now removes a package's metadata from every metadata cache directory (`metadata`, `metadata-full`, and `metadata-full-filtered`), instead of only the one the current resolution mode reads. Previously a package cached under a different mode (e.g. `metadata-full-filtered`) was left behind. Closes [#&#8203;12753](https://github.com/pnpm/pnpm/issues/12753). - Fixed an injected workspace dependency (`injectWorkspacePackages: true`) incorrectly staying as `file:` instead of deduping back to `link:` when an unrelated, ordinary shared dependency resolved to a peer-suffixed variant for the target project's own copy but not for the injected occurrence. See [#&#8203;10433](https://github.com/pnpm/pnpm/issues/10433). - `pnpm deploy` now supports workspaces that use catalogs. - Fixed `pnpm deploy` with a shared lockfile so local `file:` tarball dependencies keep their package name in the generated deploy lockfile. This prevents warm-store deploys from failing with `ERR_PNPM_UNEXPECTED_PKG_CONTENT_IN_STORE` when the tarball filename includes the version. - Options that follow `create`, `exec`, or `test` appearing as a subcommand of another command are now parsed instead of being silently treated as positional parameters. For example, `pnpm team create @org:team --registry <url>` previously ignored the `--registry` option and sent the request to the default registry. - `pnpm add -g`, `pnpm update -g`, `pnpm setup`, and the self-updater no longer fail with `ERR_PNPM_MISSING_TIME` when `trustPolicy: no-downgrade` or `resolutionMode: time-based` is set in the global config [#&#8203;12883](https://github.com/pnpm/pnpm/issues/12883). The decision to fetch full registry metadata now lives in one place, and the `no-downgrade` trust policy always requests full metadata (matching the self-updater), since the trust evidence it checks is missing from abbreviated metadata even on registries that include the `time` field. - `pnpm list` and `pnpm why` no longer crash with `EMFILE: too many open files` when a project has a large number of unsaved dependencies (packages present in `node_modules` but not in the lockfile). The reads of those packages are now concurrency-limited. - The published `pnpm` package no longer declares `dependencies` or `devDependencies`. Because the CLI bundles its runtime dependencies into `dist/node_modules`, those fields are dropped when packing, so `npm install` of the tarball no longer tries to resolve internal-only packages such as `@pnpm/test-ipc-server`. Closes [#&#8203;12955](https://github.com/pnpm/pnpm/issues/12955). - Fixed `pnpm publish --otp` and `pnpm publish --batch --otp` to send the configured OTP to the registry. - `pnpm publish` again sends the package's README to the registry as metadata, so registries can render it on the package page. The readme is always included in the published metadata (matching the npm CLI), while the `embed-readme` setting continues to control only whether the readme is written into the `package.json` inside the tarball. This restores the behavior that was lost when publishing became fully native. Closes [#&#8203;12966](https://github.com/pnpm/pnpm/issues/12966). - Fixed the dependency status check wrongly reporting "up to date" when a `package.json`, `.pnpmfile.cjs`, or patch file was edited in the same second as the previous install, on filesystems that record mtimes at whole-second resolution (for example ext4 with 128-byte inodes). The optimistic repeat-install fast path and `verify-deps-before-run` compared mtimes strictly, so a same-second edit whose mtime rounded down looked unchanged and re-resolution was skipped. Such a file's whole second is now treated as possibly-modified, falling through to the content check; behavior on sub-second filesystems is unchanged. - Retry package metadata requests when a registry or proxy returns `304 Not Modified` to an unconditional request, preventing false `ERR_PNPM_CACHE_MISSING_AFTER_304` failures [pnpm/pnpm#12882](https://github.com/pnpm/pnpm/issues/12882). If the retry also returns `304`, report `ERR_PNPM_META_NOT_MODIFIED_WITHOUT_CACHE` instead. - Fixed `pnpm update` removing transitive lockfile entries when `dedupePeerDependents` is disabled and the selected package is absent [pnpm/pnpm#12456](https://github.com/pnpm/pnpm/issues/12456). - Limit modern deploy lockfiles and localized virtual stores to dependencies reachable from the selected dependency groups. - A `tokenHelper` command is now given a 60-second time limit. A helper that hangs (deadlock, stuck I/O) is killed and reported as an error instead of leaving the command waiting forever. - Fixed orphaned child processes on Windows when pnpm exits on an error while commands spawned by `pnpm exec` or `pnpm dlx` are still running (for example, when one project's command fails during `pnpm --recursive exec`). The PIDs of these commands are now recorded when they are spawned and their whole process trees are terminated with `taskkill` on an error exit. Previously the cleanup relied on enumerating the system process list, which is so slow on Windows that the enumeration hit its timeout and the cleanup was silently skipped [#&#8203;12406](https://github.com/pnpm/pnpm/issues/12406). - `pnpm pack` now respects workspace-root `.npmignore` and `.gitignore` files when packing workspace 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.12.0`](https://github.com/pnpm/pnpm/releases/tag/v11.12.0): pnpm 11.12 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.11.0...v11.12.0) ##### Minor Changes - [`a897ef7`](https://github.com/pnpm/pnpm/commit/a897ef7): Custom fetchers exported from a pnpmfile can now delegate by returning a `{ delegate: <resolution> }` envelope: pnpm rewrites the package's resolution to the delegated shape and runs the built-in fetcher on it. This is the portable delegation form that also works in pacquet, where `cafs` and `fetchers` cannot be passed to the hook. Related to [pnpm/pnpm#11685](https://github.com/pnpm/pnpm/issues/11685). ##### Patch Changes - [`2b02764`](https://github.com/pnpm/pnpm/commit/2b02764): The changed-packages filter (`--filter "...[<since>]"`) no longer allows an option-like `<since>` value (such as `--output=<path>`) to be interpreted as a git option — git now rejects it as a bad revision. The repository root is also resolved to the nearest `.git` entry, so the filter works in a git worktree checked out inside another repository's tree. - [`43711ce`](https://github.com/pnpm/pnpm/commit/43711ce): `pnpm outdated` no longer checks the registry for dependencies that are resolved from local `link:`, `file:`, or `workspace:` references in the lockfile [#&#8203;12827](https://github.com/pnpm/pnpm/issues/12827). - [`3c6718b`](https://github.com/pnpm/pnpm/commit/3c6718b): Fixed a deadlock in peer dependency resolution: `pnpm install` hung forever when a peer dependency cycle spanned a project's own dependencies and auto-installed peer providers, for example when installing `electron-builder@26.15.3` [#&#8203;12921](https://github.com/pnpm/pnpm/issues/12921). - [`252f15e`](https://github.com/pnpm/pnpm/commit/252f15e): Fixed peer dependency auto-install picking a version the peer range rejects. In a workspace with several projects, a package declaring a peer dependency with a semver range (for example `^1.0.0`) could get the highest version found anywhere in the workspace (for example a `2.0.0` resolved for another project) instead of a version that satisfies the range. Peers are now deduplicated onto the highest preferred version that satisfies the declared range, and when none does, the range is resolved from the registry. Also fixed re-resolving with an existing lockfile hoisting a different peer version than a fresh install of the same manifest: root dependencies reused from the lockfile were invisible to peer hoisting, so a peer that a root dependency provides could be bound to another version. - [`a38adda`](https://github.com/pnpm/pnpm/commit/a38adda): `pnpm self-update <version>` now installs the requested pnpm version when it matches the currently running version but is missing from the global self-update directory. - [`6a85968`](https://github.com/pnpm/pnpm/commit/6a85968): `pnpm stage list` now stops paginating after a fail-safe cap of 1000 pages, so a misbehaving registry cannot keep the command looping forever. - [`eee7c9a`](https://github.com/pnpm/pnpm/commit/eee7c9a): `verify-deps-before-run` no longer spawns a `pnpm install` when pnpm is executed in a directory that has no `package.json`. A mistyped command run outside a project (for example `pnpm witch 10 login`) used to crash with a confusing error from the spawned install; now it fails with the regular "no package.json found" error. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.11.0`](https://github.com/pnpm/pnpm/releases/tag/v11.11.0): pnpm 11.11 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.10.0...v11.11.0) ##### Minor Changes - [`508b8c2`](https://github.com/pnpm/pnpm/commit/508b8c2): Added the `pnpm access` command for managing package access and visibility on the registry, supporting listing packages and collaborators, getting and setting package status and MFA requirements, and granting or revoking team access. ##### Patch Changes - [`c70e33e`](https://github.com/pnpm/pnpm/commit/c70e33e): Allow `allowBuilds` entries for git-hosted packages to match by repository URL without pinning the resolved commit hash. This lets trusted git repositories keep running their build scripts after branch updates without approving each new commit, while package-name-only rules still do not approve git-hosted artifacts. - [`3067e4f`](https://github.com/pnpm/pnpm/commit/3067e4f): Reduced peak memory usage during cold-cache dependency resolution. The metadata fetch is memoized for the whole resolution phase, and it was retaining each package's raw registry response body (used only to mirror the response to disk) for that entire time. The memoized cache now holds a body-less copy, so the raw body only lives as long as the call that writes the disk mirror. On large graphs that fetch full metadata (e.g. with `minimumReleaseAge` or `trustPolicy` enabled) this cuts peak RSS by roughly 30%, back in line with pnpm 10. The resolved lockfile is unchanged. - [`51300fd`](https://github.com/pnpm/pnpm/commit/51300fd): Prevent a crafted `pnpm-lock.yaml` from writing package content outside the virtual store. A dependency path key whose name reconstructs to a path-traversal sequence (e.g. `../../../tmp/x@1.0.0`) is now rejected by the isolated (virtual-store) linker and the Plug'n'Play resolver map, matching the containment already applied to the hoisted linker. Under the global virtual store, a traversal in the version-derived path segment (e.g. a snapshot `version: "../../x"`) is now rejected at `formatGlobalVirtualStorePath`, the single point every global-virtual-store slot path funnels through — closing the same escape in the isolated linker, the resolver's dependency-graph builder, and the config-dependency installer. - [`f8058eb`](https://github.com/pnpm/pnpm/commit/f8058eb): Reject symlinked `pnpm-lock.yaml` files when reading or writing the env lockfile document. - [`9318a11`](https://github.com/pnpm/pnpm/commit/9318a11): Allow `registries` and `namedRegistries` to be configured in the global `config.yaml` file. - [`51300fd`](https://github.com/pnpm/pnpm/commit/51300fd): Fixed a path traversal vulnerability where a dependency whose manifest `name` was a scoped path traversal (e.g. `@x/../../../<path>`) could be written outside `node_modules` to an attacker-controlled location during `pnpm install`, even with `--ignore-scripts`. The isolated linker now validates the package name before using it as a directory name, matching the existing protection in the hoisted linker. - [`14332f0`](https://github.com/pnpm/pnpm/commit/14332f0): Fail instead of silently removing an optional dependency's locked entries from `pnpm-lock.yaml` when the registry cannot resolve it. Previously, when registry metadata lacked a version that the lockfile already pinned (for example, a mirror that had not synced a recent release yet), `pnpm install` and `pnpm dedupe` silently dropped the optional dependency's entries — emptying maps such as the platform binaries of `@napi-rs/canvas` — so the lockfile differed between machines and frozen installs on other hosts had nothing to link [#&#8203;12853](https://github.com/pnpm/pnpm/issues/12853). - [`fecfe83`](https://github.com/pnpm/pnpm/commit/fecfe83): Fixed peer dependency resolution with `autoInstallPeers` when a workspace package depends on a version of a package that a transitive dependency's self-contained closure also provides for itself. The peer providers that are attached to the root project for reuse are no longer peer-resolved a second time in the root context, so packages inside such a closure no longer get their peers bound to the root project's incompatible version [#&#8203;4993](https://github.com/pnpm/pnpm/issues/4993). - [`5a4daec`](https://github.com/pnpm/pnpm/commit/5a4daec): `${...}` environment-variable placeholders in the `httpProxy`, `httpsProxy`, `noProxy`, `proxy`, and `noproxy` settings are no longer expanded when these settings come from a project's `pnpm-workspace.yaml`. They now receive the same protection already applied to `registry`, `namedRegistries`, and `pnprServer`. - [`d1da02e`](https://github.com/pnpm/pnpm/commit/d1da02e): `pnpm publish` no longer prints credentials when the target registry is configured with inline `user:pass@` credentials (e.g. `registry=https://user:pass@example.com/`). They are now redacted both from the "publishing to registry" line and from the OIDC (trusted publishing) failure messages. - [`dcfc611`](https://github.com/pnpm/pnpm/commit/dcfc611): `pnpm self-update` now honors `trustPolicy=no-downgrade`. It resolves the target pnpm version against full registry metadata, so it refuses to switch to a version whose supply-chain trust evidence is weaker than an earlier-published one, the same way a regular install does. - [`a8ad82d`](https://github.com/pnpm/pnpm/commit/a8ad82d): Register the `pn` alias in generated shell completion scripts. - [`25bd5c3`](https://github.com/pnpm/pnpm/commit/25bd5c3): Fixed standalone installer downgrades from pnpm v12 to v11. - [`23996e9`](https://github.com/pnpm/pnpm/commit/23996e9): `pnpm runtime set <name> <version>` now validates its arguments: the name must be `node`, `deno`, or `bun`, and the version must not contain a comma. Previously these were interpolated straight into a `pnpm add` selector, where an unsupported name or a comma (e.g. `node 22,is-positive`) could be misread as a list of packages or a local directory and install unintended packages or bins. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.10.0`](https://github.com/pnpm/pnpm/releases/tag/v11.10.0): pnpm 11.10 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.9.0...v11.10.0) ##### Minor Changes - [`e2e3c81`](https://github.com/pnpm/pnpm/commit/e2e3c81): Added the `issues` command as an alias of `bugs`, so `pnpm issues` opens the package's bug tracker URL in the browser. - [`8491f8e`](https://github.com/pnpm/pnpm/commit/8491f8e): Added the `prefix` command which prints the current package prefix directory (or global prefix directory if `-g` / `--global` is used). - [`3425e80`](https://github.com/pnpm/pnpm/commit/3425e80): Added an `_auth` setting for configuring registry authentication as a single structured (URL-keyed) value. It can be set in the **global** pnpm config (`config.yaml`) or, for CI, via the `pnpm_config__auth` environment variable. The env form sidesteps the GitHub Actions / bash / zsh limitation that broke the existing `pnpm_config_//host/:_authToken=…` form (env var names containing `/`, `:`, or `.` are silently dropped). Closes [#&#8203;12314](https://github.com/pnpm/pnpm/issues/12314). The value is keyed by registry URL so each secret is explicitly bound to the host that may receive it. Registry URL keys must use `http` or `https` and must not include credentials, query strings, or fragments: ```sh export pnpm_config__auth='{"https://registry.npmjs.org":{"@":{"authToken":"npm-token"},"@org":{"authToken":"org-token"}}}' ``` The equivalent in the global `config.yaml`: ```yaml _auth: https://registry.npmjs.org: "@": authToken: npm-token "@org": authToken: org-token ``` Within each registry URL, `@` means registry-wide/default credentials and package scopes like `@org` bind credentials to that scope on the same host. The only supported credential field is `authToken` (maps to `_authToken` / bearer auth); the deprecated `basicAuth` / `username` + `password` forms are intentionally not accepted here. Each entry also infers a trusted registry route: `@` routes the default registry (and `pnpm add <pkg>` resolves there), and `@org` routes that scope. Because the credential and destination host arrive in one trusted value, repo-controlled `pnpm-workspace.yaml` or project `.npmrc` cannot redirect the token to a different host. `_auth` is honored **only** from the env var and the global config — it is ignored in a project `pnpm-workspace.yaml` / `.npmrc`, so repo-controlled config can never supply registry auth. Precedence: CLI flags (`--registry`, `--@scope:registry`) > `pnpm_config__auth` > global `config.yaml` `_auth` > `pnpm-workspace.yaml`. Both `pnpm_config__auth` (lowercase, documented form) and `PNPM_CONFIG__AUTH` (all-caps, the shell convention some CI runners apply) are honored. If both are set, lowercase wins unless it is empty, in which case uppercase is used. The env var wins over the global `config.yaml` `_auth` on a conflicting key. `tokenHelper` is not supported in `_auth`. Parsing is strict: a malformed value (bad JSON, wrong shape, invalid registry URL or scope, an unsupported credential field) fails fast with an error rather than being silently dropped. **Pacquet parity note:** the pacquet (Rust) port supports the same single credential field as the TS CLI: `authToken`. - [`a33eeec`](https://github.com/pnpm/pnpm/commit/a33eeec): `pnpm self-update` and `packageManager` version-switching can now install and link pnpm v12 (the Rust port), published with equal content under both the `pnpm` and `@pnpm/exe` names on the `next-12` dist-tag. Its native binaries ship as `@pnpm/exe.<platform>-<arch>` packages, which pnpm's built-in installer links directly — no Node.js launcher, so the command pays no Node startup cost. v12 is initialized exactly like `@pnpm/exe`, including per-platform global-virtual-store hashing. From v12 onward the install converges on the unscoped `pnpm` package (the Rust exe) — even when updating from the SEA `@pnpm/exe` build. - [`1dd12bd`](https://github.com/pnpm/pnpm/commit/1dd12bd): When resolving through a pnpr install-accelerator server, pnpm no longer forwards its own upstream registry credentials in the resolve request. Only the `Authorization` header identifying the caller to pnpr is sent. The pnpr server now selects upstream credentials from its own route policy (operator-configured upstream credential aliases), so private dependencies resolve through a pnpr-managed alias the caller is authorized to use, rather than by sending the client's registry tokens to the server. - [`1e81761`](https://github.com/pnpm/pnpm/commit/1e81761): Expose web authentication `authUrl` and `doneUrl` in JSON error output when OTP is required in a non-interactive terminal [#&#8203;12724](https://github.com/pnpm/pnpm/issues/12724). ##### Patch Changes - [`2f389d6`](https://github.com/pnpm/pnpm/commit/2f389d6): Added the Node.js release team's new signing key (Stewart X Addison, `655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD`) to the embedded Node.js release keys, so runtimes whose `SHASUMS256.txt` is signed by the new releaser verify successfully. - [`acbdb94`](https://github.com/pnpm/pnpm/commit/acbdb94): Fixed shell tab completion not suggesting workspaces after the `-F` alias for `--filter` option. - [`dcabb78`](https://github.com/pnpm/pnpm/commit/dcabb78): Fixed `pnpm up -r <pkg>` bumping unrelated packages that have open semver ranges. Previously, any update mutation nullified the lockfile-derived `preferredVersions` globally, so packages with `^x.y.z` ranges could re-resolve to newer compatible versions even though the user only asked to update a specific package. The install layer now always seeds `preferredVersions` from the lockfile, and caller-supplied preferred versions (such as the vulnerability penalties of `pnpm audit --fix`) layer on top of the seed instead of replacing it. The targeted package still bumps: the per-resolve `updateRequested` flag makes the resolver ignore the target's own lockfile pins. Closes [#&#8203;10662](https://github.com/pnpm/pnpm/issues/10662). - [`d539172`](https://github.com/pnpm/pnpm/commit/d539172): Fixed pnpm pack and pnpm publish failing when prepack generates files that are included in the package and postpack cleans them up. - [`be6505a`](https://github.com/pnpm/pnpm/commit/be6505a): Hardened global package management: - On Windows, removing or updating a global package now also cleans up the `node.exe` flavor of a bin, so a stale `node.exe` no longer survives on `PATH` after uninstall, and a new global install no longer silently overwrites an existing `node.exe`. - `pnpm add -g pnpm@<version>` (and `@pnpm/exe@<version>`) is now rejected like the bare `pnpm` form, pointing to `pnpm self-update`. - Dependency aliases read from a global package's manifest are validated before being joined onto `node_modules` paths, preventing a tampered manifest from escaping the install directory. - Each global install group is created in its own freshly-made directory (no longer reusing a colliding or pre-existing path). - Removing or updating a global package no longer unlinks a bin that belongs to a different globally installed package. - [`25c7388`](https://github.com/pnpm/pnpm/commit/25c7388): pnpm now rejects `jsr:` specifiers whose package name is not a valid npm package name — an empty scope or name (e.g. `jsr:@scope/`), path separators inside the name, or any other shape `validate-npm-package-name` rejects — with `ERR_PNPM_INVALID_JSR_PACKAGE_NAME` instead of silently converting them into a malformed `@jsr/...` npm package name. - [`25c7388`](https://github.com/pnpm/pnpm/commit/25c7388): pnpm now rejects named-registry specifiers (e.g. `gh:`) whose package name is not a valid npm package name — an empty scope (e.g. `gh:@/bar`), path separators inside the name (e.g. `gh:@scope/../name`), or any other shape `validate-npm-package-name` rejects — with `ERR_PNPM_INVALID_NAMED_REGISTRY_PACKAGE_NAME` instead of passing the name through to registry URLs and metadata cache file paths. - [`96da7c5`](https://github.com/pnpm/pnpm/commit/96da7c5): node-gyp's `gyp_main.py` and `gyp` entrypoints are now packed with the executable bit in the `pnpm` and `@pnpm/exe` tarballs. Without it, building native addons from source could fail with a permission error. - [`99982b9`](https://github.com/pnpm/pnpm/commit/99982b9): Sped up resolution and reduced memory use against registries that ignore npm's abbreviated metadata format and always return the full package document (for example, Azure DevOps Artifacts). pnpm now strips such documents down to the abbreviated field set before caching them. Resolution output is unchanged, and registries that honor the abbreviated format (such as the npm registry) pay no extra cost. - [`11a7fdd`](https://github.com/pnpm/pnpm/commit/11a7fdd): Sped up offline and `--prefer-offline` resolution on large workspaces (e.g. `pnpm dedupe --offline`, `pnpm install --offline`). Package metadata loaded from the local cache is now kept in memory, so each package's metadata is parsed once per command instead of once per dependent that references it. - [`2c7369d`](https://github.com/pnpm/pnpm/commit/2c7369d): `pnpm pack-app` now rejects `--entry` / `pnpm.app.entry` and `--output-dir` / `pnpm.app.outputDir` values that are absolute paths or escape the project directory via `..` (or a symlink that resolves outside it), and refuses to write the produced executable when its target path already exists as a symlink (or other non-regular file). This prevents a repository-controlled `package.json` from embedding host files (such as an SSH key) into the produced executable, writing build artifacts outside the project, or overwriting an arbitrary file through a committed symlink. The new error codes are `ERR_PNPM_PACK_APP_ENTRY_OUTSIDE_PROJECT`, `ERR_PNPM_PACK_APP_OUTPUT_DIR_OUTSIDE_PROJECT`, and `ERR_PNPM_PACK_APP_OUTPUT_FILE_NOT_REGULAR`. When ad-hoc signing macOS targets, `pnpm pack-app` now runs the system `codesign` by absolute path and resolves `ldid` to a location outside the project, so a repository-controlled `node_modules/.bin` on `PATH` cannot hijack the signer. - [`ce5d5a5`](https://github.com/pnpm/pnpm/commit/ce5d5a5): Relative paths in `patchedDependencies` are now resolved against the lockfile directory when computing patch file hashes, so running `pnpm install` from a subdirectory no longer fails with `ENOENT` looking for the patch file in the wrong location [#&#8203;12762](https://github.com/pnpm/pnpm/pull/12762). - [`ebb4096`](https://github.com/pnpm/pnpm/commit/ebb4096): `pnpm peers` no longer reports a conflict for a missing peer dependency that is ignored via `pnpm.peerDependencyRules.ignoreMissing`. - [`dcabb78`](https://github.com/pnpm/pnpm/commit/dcabb78): Fixed a prototype-pollution hazard when seeding preferred versions: a dependency named `__proto__` in a manifest or in `pnpm-lock.yaml` could write through `Object.prototype` (or crash the install) while the preferred-versions map was being built. The maps are now null-prototype objects, so crafted package names land as plain keys. - [`f38e696`](https://github.com/pnpm/pnpm/commit/f38e696): Hardened `pnpm deploy --force` so it refuses unsafe deploy targets such as workspace roots, parent directories, out-of-workspace paths, and symlinked target parents. - [`806c3ec`](https://github.com/pnpm/pnpm/commit/806c3ec): pnpm no longer warns about ignored project-level auth settings when `PNPM_CONFIG_NPMRC_AUTH_FILE` points at the project `.npmrc` — setting it to that file is an explicit opt-in to trusting it, so auth env variables in it are expanded [pnpm/pnpm#12480](https://github.com/pnpm/pnpm/issues/12480). - [`991405e`](https://github.com/pnpm/pnpm/commit/991405e): Restore differential rendering (`ansi-diff`) to fix duplicated output lines introduced by [#&#8203;12351](https://github.com/pnpm/pnpm/issues/12351). - [`c121235`](https://github.com/pnpm/pnpm/commit/c121235): Fixed the topological order of `--filter`ed commands (`pnpm run`, `pnpm exec`, `pnpm publish`, `pnpm pack`, `pnpm rebuild`) when the selected projects depend on each other only transitively through projects that were not selected. Previously such selected projects could run concurrently or in the wrong order; now a project always runs after the selected projects it transitively depends on, while projects without a real dependency relationship still run concurrently. This now also holds for prod-only filters (`--filter-prod`), which resolve order through the production dependency graph so transitive production dependencies are respected without pulling back the dev dependencies the filter drops, and for selections that mix `--filter` with `--filter-prod` [#&#8203;8335](https://github.com/pnpm/pnpm/issues/8335). - [`d539172`](https://github.com/pnpm/pnpm/commit/d539172): `pnpm pack` and `pnpm publish` no longer follow a symlinked workspace `LICENSE` file when injecting it into a package that has no license of its own. Following the symlink could pack bytes from outside the workspace into the published tarball. - [`dcabb78`](https://github.com/pnpm/pnpm/commit/dcabb78): Fixed `pnpm up <pkg>` producing a different result than a fresh install of the same manifests would. The resolver now distinguishes `updateRequested` (true only for packages that match the user's update target) from the broader `update` flag, and for the targeted package ignores only its own lockfile-derived preferred-version pins — so the target re-resolves exactly as if its lockfile entries were deleted and `pnpm install` ran. Preferred versions a fresh install applies (manifest pins, versions propagated down the dependency chain, and the vulnerability-avoidance penalties of `pnpm audit --fix`) stay in effect, so an update never installs duplicate versions that a reinstall from scratch would not reproduce. When a preferred version holds the update target below the newest version its range admits, pnpm now prints a warning explaining that reaching the newer version everywhere requires an override. - [`dcabb78`](https://github.com/pnpm/pnpm/commit/dcabb78): `pnpm update <dep>@<version>` now prints a warning when `<dep>` is only present as a transitive dependency: the requested version cannot be applied there (updates resolve the target the way a fresh install would), and the warning recommends adding the version to `pnpm.overrides` instead, which is the mechanism that does pin transitive dependencies. Closes [#&#8203;12744](https://github.com/pnpm/pnpm/issues/12744). - [`a6c4d5f`](https://github.com/pnpm/pnpm/commit/a6c4d5f): When a dependency cannot be found in the registry (404) or the registry has no matching version, and a workspace project with the same name exists only at non-matching versions, the error now reports the available workspace versions (`ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE`) instead of the raw registry failure [pnpm/pnpm#1379](https://github.com/pnpm/pnpm/issues/1379). Other registry failures (authorization, network, server errors) still propagate unchanged. The pacquet (Rust) resolver applies the same behavior. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.9.0`](https://github.com/pnpm/pnpm/releases/tag/v11.9.0): pnpm 11.9 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.8.0...v11.9.0) ##### Minor Changes - [`bae694f`](https://github.com/pnpm/pnpm/commit/bae694f): Some registries generate tarballs on-demand and cannot provide an integrity checksum in their package metadata. In that case pnpm now computes the integrity from the downloaded tarball and stores it in the lockfile, so the entry is verifiable on subsequent installs instead of being written without an integrity (which would fail the next install). This also applies to `--lockfile-only`: the tarball is downloaded so its integrity can be computed. A lockfile entry that is still missing its integrity is rejected as a `ERR_PNPM_MISSING_TARBALL_INTEGRITY` lockfile verification violation (the install fails closed) rather than being silently re-fetched. - [`6c35a43`](https://github.com/pnpm/pnpm/commit/6c35a43): Added `--exclude-peers` to `pnpm sbom`. With `auto-install-peers` (the default), peer dependencies resolve into the lockfile and are otherwise indistinguishable from the package's own dependencies. The flag drops peer dependencies (and any transitive subtree reachable only through them) from the SBOM. CycloneDX 1.7 has no scope or relationship that expresses "consumer-provided peer", so omission is the only spec-clean handling. The flag name matches `pnpm list --exclude-peers`; note the SBOM flag prunes a peer's exclusive subtree, which is stricter than `pnpm list` (which only hides leaf peers). ##### Patch Changes - [`25a829e`](https://github.com/pnpm/pnpm/commit/25a829e): `pnpm audit --fix` now writes a single combined `minimumReleaseAgeExclude` entry per package (e.g. `axios@0.18.1 || 0.21.1`) instead of one entry per version, matching the format documented for the setting. Existing per-version entries in `pnpm-workspace.yaml` are merged into the combined form rather than left as duplicates. Installs that auto-collect immature versions into `minimumReleaseAgeExclude` now report the same combined entries, so the "Added N entries" message matches what is written to the manifest [#&#8203;12534](https://github.com/pnpm/pnpm/issues/12534). - [`1cbb5f2`](https://github.com/pnpm/pnpm/commit/1cbb5f2): Fixed non-deterministic peer resolution that could add or remove an optional transitive peer — for example `@babel/core`, reached through `styled-jsx` — from a package's peer-dependency suffix across otherwise identical installs, churning the lockfile and causing intermittent `pnpm dedupe --check` failures in CI. When a package's children are resolved by one occurrence (the "owner") and reused by a deeper consumer, whether that consumer inherited the owner's missing peers depended on whether the owner's resolution had finished yet — a race under concurrent resolution. The decision is now a function of the dependency graph's structure rather than resolution-completion order. - [`d577eea`](https://github.com/pnpm/pnpm/commit/d577eea): Fixed a Windows flakiness in `pnpm dlx` where a failed install could surface a spurious `EBUSY: resource busy or locked` error. The cleanup of a partially-populated dlx cache is now best-effort with retries and no longer masks the original error. - [`ec7cf70`](https://github.com/pnpm/pnpm/commit/ec7cf70): Shortened the `pnpm dlx` cache path so deep dependency trees no longer overflow Windows' `MAX_PATH`, which could make a dependency's lifecycle script fail with `spawn cmd.exe ENOENT`. - [`05b95ab`](https://github.com/pnpm/pnpm/commit/05b95ab): Fixed `pnpm` hanging (and crashing with an unhandled promise rejection) when a non-retryable network error such as `SELF_SIGNED_CERT_IN_CHAIN` occurs while fetching from a registry. The error is now rejected through the returned promise instead of being thrown inside the detached retry callback. - [`d3f68e2`](https://github.com/pnpm/pnpm/commit/d3f68e2): Fix a `pnpm audit` performance regression on lockfiles that contain dependency cycles. The reachable-vulnerability pruning added in pnpm 11.5.1 only memoized acyclic subtrees, so any node whose subtree touched a cycle — together with all of its ancestors — was recomputed on every query, making the path walk quadratic. Reachability is now computed once per node using Tarjan's strongly-connected-components algorithm, so cyclic graphs are handled in linear time [#&#8203;12212](https://github.com/pnpm/pnpm/issues/12212). The audit path walk also no longer recurses, so a deeply nested dependency graph can no longer overflow the call stack, and the install path to each finding is tracked without per-node copying, keeping memory linear in the graph depth. - [`322f88f`](https://github.com/pnpm/pnpm/commit/322f88f): Fix failed optional dependency updates so they don't rewrite unrelated dependency specs [#&#8203;11267](https://github.com/pnpm/pnpm/issues/11267). - [`1488db1`](https://github.com/pnpm/pnpm/commit/1488db1): When `enableGlobalVirtualStore` is toggled on for a project that was previously installed without it, stale hoisted symlinks under `node_modules/.pnpm/node_modules` are now replaced instead of being left pointing at the old per-project virtual store location [#&#8203;9739](https://github.com/pnpm/pnpm/issues/9739). - [`6545793`](https://github.com/pnpm/pnpm/commit/6545793): Fixed `pnpm install --ignore-workspace` overwriting the `allowBuilds` map in `pnpm-workspace.yaml`. The ignored builds of a package with a build script were auto-populated into `allowBuilds` even though `--ignore-workspace` was passed, clobbering committed `true`/`false` values with the `set this to true or false` placeholder [#&#8203;12469](https://github.com/pnpm/pnpm/issues/12469). - [`fbdc0eb`](https://github.com/pnpm/pnpm/commit/fbdc0eb): Fixed `minimumReleaseAgeExclude` and `trustPolicyExclude` so multiple exact-version entries for the same package behave the same as a single `||` disjunction entry. Previously only the first matching rule's versions were honored, so a config like `[form-data@4.0.6, form-data@2.5.6]` could still flag `form-data@2.5.6` as violating `minimumReleaseAge`, while `[form-data@4.0.6 || 2.5.6]` worked as expected [#&#8203;12463](https://github.com/pnpm/pnpm/issues/12463). - [`fa7004b`](https://github.com/pnpm/pnpm/commit/fa7004b): The in-memory package metadata cache is now populated on the exact-version disk fast path, so repeated resolutions of the same package within one install no longer re-read and re-parse the on-disk metadata. In large monorepos this brings the time for adding a new package down from minutes to seconds. The in-memory cache key now also includes the registry, so a package of the same name served by two different registries in a single install can no longer share a cache slot and resolve the wrong tarball. - [`0a154b1`](https://github.com/pnpm/pnpm/commit/0a154b1): Fixed `pnpm patch` dropping the package name (and leaking internal option fields) when the patched dependency resolves to a single git-hosted version. - [`4d3fe4b`](https://github.com/pnpm/pnpm/commit/4d3fe4b): The pnpr resolver endpoints moved under the reserved `/-/pnpr` namespace: `POST /v1/resolve` is now `POST /-/pnpr/v0/resolve` and `POST /v1/verify-lockfile` is now `POST /-/pnpr/v0/verify-lockfile`. The capability handshake at `GET /-/pnpr` advertises protocol version `0` to match. This keeps every pnpr-proprietary route in npm's reserved namespace, so it can never collide with a package path. - [`0ec878d`](https://github.com/pnpm/pnpm/commit/0ec878d): Removing a runtime dependency now removes the matching `devEngines.runtime` or `engines.runtime` entry that was materialized from it. Blank runtime selectors are normalized to `latest`. - [`17e7f2c`](https://github.com/pnpm/pnpm/commit/17e7f2c): `pnpm sbom` now emits a CycloneDX `issue-tracker` external reference for components (and the root) whose `package.json` declares a `bugs` URL. Email-only `bugs` entries are skipped, since the reference requires a URL. - [`a84d2a1`](https://github.com/pnpm/pnpm/commit/a84d2a1): Add `@pnpm/resolving.tarball-url`, which builds and recognizes the canonical npm tarball URL of a package. It vendors `getNpmTarballUrl` (previously the external `get-npm-tarball-url` package) and adds `isCanonicalRegistryTarballUrl`, the predicate the lockfile writer uses to decide whether a tarball URL is derivable from name+version+registry (and can therefore be omitted from `pnpm-lock.yaml`). Exposing `isCanonicalRegistryTarballUrl` lets a custom resolver (pnpmfile `resolvers`) fronting a proxy that serves tarballs on a non-canonical path (e.g. an ephemeral `localhost:<port>`) rewrite the resolved tarball to the canonical form, so nothing host-specific is persisted to the lockfile. Previously this logic was private to `@pnpm/lockfile.utils`. Two correctness fixes are included while consolidating the logic: the scoped-package unescape now handles uppercase `%2F` as well as `%2f` (percent-encoding is case-insensitive), and protocol-insensitive comparison strips only a leading `http(s)://` scheme instead of splitting on the first `://` (which could truncate URLs containing a later `://`). - [`852d537`](https://github.com/pnpm/pnpm/commit/852d537): Lockfile verification no longer reports a registry metadata fetch failure (for example a `403`/`401` on a private registry, or a network error) as `ERR_PNPM_TARBALL_URL_MISMATCH`. When the registry can't be reached to verify an entry, the install now aborts with the registry's own fetch error (such as `ERR_PNPM_FETCH_403`, which already explains the authentication situation) instead of mislabeling a transport failure as lockfile tampering. Registry fetch errors no longer leak basic-auth credentials embedded in the registry URL (`https://user:pass@host/`) into their message. <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.8.0`](https://github.com/pnpm/pnpm/releases/tag/v11.8.0): pnpm 11.8 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.7.0...v11.8.0) ##### Minor Changes - [`c112b61`](https://github.com/pnpm/pnpm/commit/c112b61): Added a `--dry-run` option to `pnpm install`. It runs a full dependency resolution and reports what an install would change, but writes nothing to disk (no lockfile, no `node_modules`) and always exits with code 0. This mirrors the preview semantics of `npm install --dry-run` [#&#8203;7340](https://github.com/pnpm/pnpm/issues/7340). - [`179ebc4`](https://github.com/pnpm/pnpm/commit/179ebc4): `pnpm run --no-bail` now exits with a non-zero exit code when any of the executed scripts fail, while still running every matched script to completion. This makes the exit-code behavior of `--no-bail` consistent between recursive and non-recursive runs (recursive runs already failed at the end). Previously, a non-recursive `pnpm run --no-bail` always exited with code 0, even when a script failed [#&#8203;8013](https://github.com/pnpm/pnpm/issues/8013). - [`0474a9c`](https://github.com/pnpm/pnpm/commit/0474a9c): Added support for generating Node.js package maps at `node_modules/.package-map.json` during isolated and hoisted installs. Added the `node-experimental-package-map` setting to inject the generated map into pnpm-managed Node.js script environments, and the `node-package-map-type` setting to choose between `standard` and `loose` package maps. - [`dcededc`](https://github.com/pnpm/pnpm/commit/dcededc): `pnpm sbom` now marks components reachable only through `devDependencies` with CycloneDX `scope: "excluded"` and the `cdx:npm:package:development` property. The `excluded` scope documents "component usage for test and other non-runtime purposes", which matches the semantics of a devDependency; the property is the CycloneDX npm-taxonomy marker emitted by `@cyclonedx/cyclonedx-npm`, so both modern (scope) and existing (property) consumers are covered. Components reachable at runtime (including installed `optionalDependencies`) omit `scope` and default to `required`. - [`1495cb0`](https://github.com/pnpm/pnpm/commit/1495cb0): Added per-package SBOM generation with `--out` and `--split` flags. Use `--out out/%s.cdx.json` to write one SBOM per workspace package to individual files, or `--split` for NDJSON output to stdout. When `--filter` selects a single package, the SBOM root component now uses that package's metadata. Workspace inter-dependencies (`workspace:` protocol) and their transitive dependencies are included. Author, repository, and license fall back to the root manifest when the package doesn't define them. - [`293921a`](https://github.com/pnpm/pnpm/commit/293921a): feat(view): support searching project manifest upward when package name is omitted When running `pnpm view` without a package name, the command now searches upward for the nearest project manifest (`package.json`, `package.yaml`, or `package.json5`) and uses its `name` field. If the manifest exists but lacks a `name` field, an error is thrown. This change also replaces the `find-up` dependency with `empathic` for improved performance and consistency across workspace tools. ##### Patch Changes - [`29ab905`](https://github.com/pnpm/pnpm/commit/29ab905): Fixed `pnpm update` overriding the version range policy of a named catalog whose name parses as a version (e.g. `catalog:express4-21`). The `catalog:` reference carries no pinning of its own, so the prefix from the catalog entry (such as `~`) is now preserved instead of being widened to `^` [#&#8203;10321](https://github.com/pnpm/pnpm/issues/10321). - [`bee4bf4`](https://github.com/pnpm/pnpm/commit/bee4bf4): Security: validate config dependency names and versions from the env lockfile (`pnpm-lock.yaml`) before using them to build filesystem paths. A committed lockfile with a traversal-shaped `configDependencies` name (such as `../../PWNED`) or version (such as `../../../PWNED`) could previously cause `pnpm install` to create symlinks or write package files outside `node_modules/.pnpm-config` and the store. Names must now be valid npm package names and versions must be exact semver versions; the same validation is applied to optional subdependencies of config dependencies, and to the legacy workspace-manifest format before any lockfile is written. See [GHSA-qrv3-253h-g69c](https://github.com/pnpm/pnpm/security/advisories/GHSA-qrv3-253h-g69c). - [`96bdd57`](https://github.com/pnpm/pnpm/commit/96bdd57): Fix `link:` workspace protocol switching to `file:` after `pnpm rm` is run from inside a workspace package whose target workspace dependency has its own dependencies, when `injectWorkspacePackages: true` is set. Follow-up to [#&#8203;10575](https://github.com/pnpm/pnpm/pull/10575), which fixed the same symptom for workspace packages without dependencies. - [`302a2f7`](https://github.com/pnpm/pnpm/commit/302a2f7): No longer warn about using both `packageManager` and `devEngines.packageManager` when the two fields pin the same package manager at the same version with the same integrity hash (e.g. both `pnpm@11.5.1+sha512.…`). Previously the hash was stripped from the legacy `packageManager` field but not from `devEngines.packageManager`, so even identical specifications looked like a mismatch [#&#8203;12028](https://github.com/pnpm/pnpm/issues/12028). The warning still fires on any genuine divergence, and several cases now state the specific reason instead of a single generic message: a different package manager, a different version, or contradictory integrity hashes for the same version. - [`3f0fb21`](https://github.com/pnpm/pnpm/commit/3f0fb21): Fixed the progress line showing leftover characters from external processes that write to the terminal between progress updates (e.g. an SSH passphrase prompt would leave a fragment like `added 0sa':`). The interactive reporter now redraws each frame in place, erasing to the end of the display before reprinting, so any such remnants are cleared [#&#8203;12350](https://github.com/pnpm/pnpm/issues/12350). - [`564619f`](https://github.com/pnpm/pnpm/commit/564619f): Fixed `pnpm approve-builds` reporting "no packages awaiting approval" when a build-script dependency whose approval was revoked (e.g. after `git stash` drops the `allowBuilds` from `pnpm-workspace.yaml`) is re-added. The revoked packages are now correctly recorded in `.modules.yaml` so `approve-builds` can find them. [#&#8203;12221](https://github.com/pnpm/pnpm/issues/12221) - [`3d1fd20`](https://github.com/pnpm/pnpm/commit/3d1fd20): Skip the redundant "target bin directory already contains an exe called node" warning on Windows when the existing `node.exe` already matches the target (same hard link or identical content) [pnpm/pnpm#12203](https://github.com/pnpm/pnpm/issues/12203). - [`1b02b47`](https://github.com/pnpm/pnpm/commit/1b02b47): Fix macOS Gatekeeper blocking native binaries (`.node`, `.dylib`, `.so`) by removing the `com.apple.quarantine` extended attribute after importing them from the store. When pnpm imports files from its content-addressable store into `node_modules`, macOS preserves extended attributes, including `com.apple.quarantine`. If this xattr is present on a store blob (e.g. it was first written under a Gatekeeper-enabled app such as a Git client), it propagates to `node_modules`, and Gatekeeper blocks the native binary from loading even though pnpm already verified the file's integrity against the lockfile. After importing a package, pnpm now strips `com.apple.quarantine` from its native binaries, matching Homebrew's behaviour of dropping quarantine from verified downloads. The cleanup is macOS-only, runs in a single batched `xattr` call per package, is restricted to native binaries (other files are untouched), and is non-fatal (it logs a warning on unexpected errors). Fixes [#&#8203;11056](https://github.com/pnpm/pnpm/issues/11056) - [`61969fb`](https://github.com/pnpm/pnpm/commit/61969fb): Fix `pnpm install` with `optimisticRepeatInstall` incorrectly reporting `Already up to date` when `pnpm-lock.yaml` changed but project manifests did not. This affected workflows such as checking out or restoring only the lockfile [#&#8203;12100](https://github.com/pnpm/pnpm/issues/12100). Also fixes `checkDepsStatus` to use the correct lockfile path when `useGitBranchLockfile` is enabled, so the optimistic fast-path and lockfile modification detection work with `pnpm-lock.<branch>.yaml` files instead of always stat'ing `pnpm-lock.yaml`. Merge-conflict detection now reads the resolved lockfile name as well, and with `mergeGitBranchLockfiles` enabled every `pnpm-lock.*.yaml` is scanned for modifications and conflicts. The git branch is now resolved by reading `.git/HEAD` directly (no process spawn) and uses the workspace directory rather than `process.cwd()`. - [`5c12968`](https://github.com/pnpm/pnpm/commit/5c12968): Fix recursive updates of transitive dependencies when the update command mixes transitive dependency patterns with direct dependency selectors. For example, `pnpm up -r "@babel/core" uuid` now updates matching transitive `@babel/core` dependencies even when `uuid` is a direct dependency selector [#&#8203;12103](https://github.com/pnpm/pnpm/issues/12103). - [`9d79ba1`](https://github.com/pnpm/pnpm/commit/9d79ba1): Register the `pnpm update --no-save` flag in the CLI help and option parser. - [`0474a9c`](https://github.com/pnpm/pnpm/commit/0474a9c): Fixed `pnpm import` for Yarn v2 lockfiles when `js-yaml` v4 is installed. - [`9e0c375`](https://github.com/pnpm/pnpm/commit/9e0c375): Fixed `pnpm install` repeatedly prompting to remove and reinstall `node_modules` in a workspace package when `enableGlobalVirtualStore` is enabled. The post-install build step recorded a per-project `node_modules/.pnpm` virtual store directory in `node_modules/.modules.yaml`, overwriting the global `<storeDir>/links` value the install step had written. The next install then detected a virtual-store mismatch (`ERR_PNPM_UNEXPECTED_VIRTUAL_STORE`). The build step now derives the same global virtual store directory as the install step [#&#8203;12307](https://github.com/pnpm/pnpm/issues/12307). - [`223d060`](https://github.com/pnpm/pnpm/commit/223d060): Document the `--cpu`, `--os` and `--libc` flags in the output of `pnpm install --help`. These flags were already supported but were only documented on the website [#&#8203;12359](https://github.com/pnpm/pnpm/issues/12359). - [`e85aea2`](https://github.com/pnpm/pnpm/commit/e85aea2): Avoid reading `README.md` from disk when publishing if the publish manifest already provides a `readme` field. The README is now only read lazily, inside `createExportableManifest`, when it is actually needed. - [`3188ae7`](https://github.com/pnpm/pnpm/commit/3188ae7): Fixed `pnpm peers check` to accept loose peer dependency ranges such as `>=3.16.0 || >=4.0.0-` when the installed peer version satisfies the range [#&#8203;12149](https://github.com/pnpm/pnpm/issues/12149). - [`531f2a3`](https://github.com/pnpm/pnpm/commit/531f2a3): Fixed `pnpm update` rewriting a `workspace:` dependency that points at a local path (e.g. `workspace:../packages/foo/dist`) into a normalized `link:` or version-range specifier. Such specifiers are now preserved verbatim when the workspace protocol is preserved [#&#8203;3902](https://github.com/pnpm/pnpm/issues/3902). - [`fe66535`](https://github.com/pnpm/pnpm/commit/fe66535): Fixed a lockfile non-convergence bug where an incremental install kept a duplicate transitive dependency that a fresh install would not produce. When a package is reused from the lockfile, its child edges are taken verbatim and bypass the preferred-versions walk, so a transitive dependency could stay pinned to an older version even after a direct dependency resolved to a higher version that satisfies the same range. The resolver now refreshes such a stale pin to the higher direct-dependency version during resolution — so the older version is never resolved or fetched, and the incremental result converges to the fresh one. - [`6d35338`](https://github.com/pnpm/pnpm/commit/6d35338): `pnpm install` detects changes inside local file dependencies again. The optimistic repeat-install fast path only tracks manifest and lockfile modification times, so edits inside a local dependency's directory (or a repacked local tarball) were reported as "Already up to date". Projects with local file dependencies (`file:` and bare local path or tarball specifiers, declared directly or through `pnpm.overrides`) now always run a full install, which refetches those dependencies, matching pnpm v10 behavior [#&#8203;11795](https://github.com/pnpm/pnpm/issues/11795). - [`4ca9247`](https://github.com/pnpm/pnpm/commit/4ca9247): Preserve the existing Node.js runtime version prefix when resolving `node@runtime:<range>` to a concrete version. - [`30c7590`](https://github.com/pnpm/pnpm/commit/30c7590): Create shorter CAFS temporary package directories to leave room for lifecycle scripts that create IPC socket paths under TMPDIR. - [`13815ad`](https://github.com/pnpm/pnpm/commit/13815ad): Reporter output (warnings, progress) for `pnpm store` and `pnpm config` subcommands now goes to stderr instead of stdout. This fixes scripts that capture their stdout (e.g. `PNPM_STORE=$(pnpm store path)`, `pnpm config list --json | jq`) from getting warnings mixed into the result. - [`1c05876`](https://github.com/pnpm/pnpm/commit/1c05876): Avoid relinking unchanged child dependencies and remove stale child links during warm installs. - [`817f99d`](https://github.com/pnpm/pnpm/commit/817f99d): Fixed lockfile churn where a package's `transitivePeerDependencies` could be dropped (and shift between packages) when the package participates in a dependency cycle. A cycle re-entry resolves against truncated children, so it must not be cached as "pure"; otherwise sibling occurrences of the same package short-circuit and lose transitive peers depending on traversal order [#&#8203;5108](https://github.com/pnpm/pnpm/issues/5108). - [`eba03e0`](https://github.com/pnpm/pnpm/commit/eba03e0): Fix `pnpm install` reporting "Already up to date" after a catalog entry in `pnpm-workspace.yaml` was reverted to a previous version. After an update modified a catalog, the workspace state cache stored the pre-update catalog versions, so reverting the entry back to its original version was not detected as an outdated state [#&#8203;12418](https://github.com/pnpm/pnpm/issues/12418). - [`3b54d79`](https://github.com/pnpm/pnpm/commit/3b54d79): `pnpm update` now keeps lockfile `overrides` that resolve through a catalog in sync with the catalog. Previously, when an override referenced a catalog (e.g. `overrides: { foo: 'catalog:' }`) and `pnpm update` bumped that catalog entry, the lockfile's `catalogs` advanced while the resolved `overrides` kept the old version. The resulting lockfile was internally inconsistent, so a later `pnpm install --frozen-lockfile` failed with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`. - [`9d0a300`](https://github.com/pnpm/pnpm/commit/9d0a300): Fixed `pnpm version --recursive` so it honors the workspace selection. In recursive mode the version bump now applies to the packages resolved from the workspace filter (`selectedProjectsGraph`), matching the behavior of `pnpm publish --recursive`, instead of always bumping every workspace package [#&#8203;11348](https://github.com/pnpm/pnpm/issues/11348). <!-- 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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"><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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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" rel="noopener noreferrer"> <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 --> ### [`v11.7.0`](https://github.com/pnpm/pnpm/releases/tag/v11.7.0): pnpm 11.7 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.6.0...v11.7.0) ##### Minor Changes - Added a new setting `frozenStore` (`--frozen-store`) that lets `pnpm install` run against a package store on a read-only filesystem (e.g. a Nix store, a read-only bind mount, an OCI layer). When enabled, pnpm opens the store's SQLite `index.db` through the `immutable=1` URI — bypassing the WAL/`-shm` sidecar creation that otherwise fails on a read-only directory — and suppresses every store-write path (the `index.db` writer and the project-registry write). Pair it with `--offline --frozen-lockfile` against a fully-populated store. Under the global virtual store, package directories live inside the store, so if the store is missing the build output of a package whose lifecycle scripts are approved (or that has a patch), pnpm fails up front with `ERR_PNPM_FROZEN_STORE_NEEDS_BUILD` rather than crashing mid-build on a read-only write — seed the store with those builds first. Incompatible with `--force` and with a configured pnpr server, since both write into the store; the side-effects cache is likewise not written under `frozenStore`. If the store is missing its content directory, the install fails fast with `ERR_PNPM_FROZEN_STORE_INCOMPLETE` rather than attempting to initialize it. The read-only `immutable=1` open requires Node.js >=22.15.0, >=23.11.0, or >=24.0.0; on older runtimes `--frozen-store` fails with a clear `ERR_PNPM_FROZEN_STORE_UNSUPPORTED_NODE` error. Bin-linking also tolerates a read-only store: under the global virtual store a package's bin source lives inside the store, so the `chmod` that makes it executable would be refused — with `EPERM`/`EACCES`, or with `EROFS` on a genuinely read-only filesystem. That `chmod` is redundant when the seed already ships its bins executable with a normalized shebang, so it is now skipped in that case, while a non-executable bin (or one still carrying a Windows CRLF shebang) on a read-only store still errors. - When [`pacquet`](https://github.com/pnpm/pnpm/tree/main/pacquet) (the Rust port of pnpm) is declared in `configDependencies`, pnpm now delegates dependency **resolution** to it too — not just materialization — provided the installed pacquet is new enough to support full resolving installs (>= 0.11.7). Previously pacquet only ran in frozen-install mode: pnpm always resolved the dependency graph itself (writing `pnpm-lock.yaml`) and handed pacquet a finished lockfile to fetch / import / link. With pacquet >= 0.11.7, a non-frozen `pnpm install` (default isolated `nodeLinker`, plain install) is delegated to pacquet end-to-end in a single pass — pacquet resolves the manifests, writes the lockfile, and materializes `node_modules`. pnpm detects the capability from the installed pacquet's version; older pacquet releases keep the resolve-then-materialize split, and `add` / `update` / `remove` still resolve in pnpm (it has to mutate the manifests first). This remains an opt-in preview of the Rust install engine [#&#8203;11723](https://github.com/pnpm/pnpm/issues/11723). - Added a new opt-in `--batch` flag to `pnpm publish --recursive` that sends all selected packages to the registry in a single `PUT /-/pnpm/v1/publish` request instead of one request per package. The target registry has to implement the batch publish endpoint (pnpr does); registries that don't are reported with a clear `ERR_PNPM_BATCH_PUBLISH_UNSUPPORTED` error. The batch is processed all-or-nothing by pnpr: if any package in the batch fails validation, none of the packages are published. ##### Patch Changes - Reject path-traversal and reserved dependency aliases (such as `../../../escape`, `.bin`, `.pnpm`, or `node_modules`) that come from a lockfile rather than a freshly resolved manifest. A crafted lockfile alias could otherwise be joined directly under a hoisted `node_modules` directory, letting package files be written outside the intended install root or overwrite pnpm-owned layout. The fix adds two layers: - The `nodeLinker: hoisted` graph builder now validates each alias at the directory sink (`safeJoinModulesDir`), matching the validation pnpm already performs when resolving aliases from manifests. - The lockfile verification gate (`verifyLockfileResolutions`) now runs an always-on, policy-independent check that rejects any importer or snapshot dependency alias that is not a valid package name, failing the install early — before any fetch or filesystem work — for every node linker at once. - Made shared package child resolution deterministic when the same package is reached through multiple contexts. pnpm now chooses the shallowest occurrence, then importer order, then parent path, instead of letting request timing decide the child context and missing-peer report [pnpm/pnpm#12358](https://github.com/pnpm/pnpm/issues/12358). - Fix garbled summary line after submitting `pnpm update -i` and `pnpm audit --fix -i`. The interactive checkbox prompt previously printed every selected choice's full table row (label, current/target versions, workspace, URL) joined by commas, producing a wall of text after pressing Enter. The summary now lists only the selected package names (or vulnerability keys) by setting an explicit `short` per choice; the in-progress selection UI is unchanged. - Prevent `pnpm patch-remove` from removing files outside the configured patches directory. - Fixed `pnpm publish` ignoring `strictSsl: false` when publishing to registries with self-signed certificates. The `strictSSL` option is now forwarded to `libnpmpublish` / `npm-registry-fetch` so that `strict-ssl=false` in `.npmrc` or `strictSsl: false` in `pnpm-workspace.yaml` is respected during publish, the same way it is for `pnpm install` [pnpm/pnpm#12012](https://github.com/pnpm/pnpm/issues/12012). - Fixed `Cannot destructure property 'manifest' of 'manifestsByPath[rootDir]' as it is undefined` regression introduced in 11.6.0 when running `pnpm add <pkg>` outside a workspace on Windows. `selectProjectByDir` was keying the resulting `ProjectsGraph` by `opts.dir` instead of `project.rootDir`, so downstream `manifestsByPath` lookups missed when the two paths normalized differently (typically drive-letter casing). [pnpm/pnpm#12379](https://github.com/pnpm/pnpm/issues/12379) - Git dependencies that point to a subdirectory of a repository (`repo#commit&path:/sub/dir`) keep their `path` in the lockfile again. Since the integrity of git-hosted tarballs started being pinned in the lockfile, any install that actually downloaded the tarball rebuilt the lockfile resolution as `{ integrity, tarball, gitHosted }` and dropped the `path` field, while installs served from the store kept it — so the field disappeared seemingly at random. Without `path`, later installs from that lockfile silently unpacked the repository root instead of the subdirectory [#&#8203;12304](https://github.com/pnpm/pnpm/issues/12304). - Fixed nondeterministic lockfile output that made `pnpm dedupe --check` fail intermittently in CI. When a locked peer provider was pinned for a dependency that has no child dependencies of its own, the pinned provider leaked into the shared parent scope, so siblings resolved after it could pick up an optional peer they should not see. Which siblings were affected depended on resolution order, which varies with network timing. - Sped up `pnpm install` with a frozen lockfile by running lockfile verification (the policy revalidation gate added for `minimumReleaseAge`/`trustPolicy` and the tarball-URL anti-tamper check) concurrently with fetching and linking instead of blocking the whole install on it. Dependency lifecycle scripts are still held back until verification succeeds, so no script runs on an unverified lockfile: if verification fails the install aborts before any dependency build, and if linking finishes first the install waits for the verification verdict before completing. - User-defined `npm_config_*` environment variables are now preserved during lifecycle script execution. Previously, all `npm_`-prefixed env vars were stripped, which caused user-set variables like `npm_config_platform_arch` to be lost [pnpm/pnpm#12399](https://github.com/pnpm/pnpm/issues/12399). - pnpm can now use different auth tokens for different package scopes, even when those scopes use the same registry URL. Previously, auth was selected only by registry URL. If `@org-a` and `@org-b` both used `https://npm.pkg.github.com/`, they had to share the same token. This caused problems for registries that issue tokens per organization or per scope. Configure a scope-specific token by adding the package scope after the registry URL in the auth key: ```ini @org-a:registry=https://npm.pkg.github.com/ @org-b:registry=https://npm.pkg.github.com/ //npm.pkg.github.com/:@org-a:_authToken=${ORG_A_TOKEN} //npm.pkg.github.com/:@org-b:_authToken=${ORG_B_TOKEN} //npm.pkg.github.com/:_authToken=${FALLBACK_TOKEN} ``` `pnpm login --registry=https://npm.pkg.github.com --scope=@org-a` writes the token to the same scope-specific auth key. When installing or publishing `@org-a/*`, pnpm uses `ORG_A_TOKEN`. For `@org-b/*`, pnpm uses `ORG_B_TOKEN`. Packages without a matching scope continue to use the registry-wide fallback token. - `pnpm setup` no longer prompts to approve build scripts for `@pnpm/exe` when installing the standalone executable. pnpm links the platform-specific binary itself, so the package's install scripts are skipped during the global self-install [#&#8203;12377](https://github.com/pnpm/pnpm/issues/12377). - Close lockfile reads deterministically before rewriting lockfiles and keep pacquet's virtual store directory length aligned with pnpm on Windows. - A `304 Not Modified` answer from the registry now renews the cached metadata file's mtime, so the `minimumReleaseAge` freshness shortcut keeps serving resolutions from the cache. Previously, once a cached packument grew older than `minimumReleaseAge`, every subsequent install re-validated it against the registry forever, because a 304 never rewrites the file. - Updated dependency ranges. Notably: - `@pnpm/logger` peer dependency range moved to `^1100.0.0`. - `msgpackr` 1.11.8 → 2.0.4 (store index files remain byte-compatible in both directions). - `open` ^7.4.2 → ^11.0.0, `memoize` ^10 → ^11, `cli-truncate` ^5 → ^6, `pidtree` ^0.6 → ^1. - `@yarnpkg/core` 4.5.0 → 4.8.0, `@rushstack/worker-pool` 0.7.7 → 0.7.18, `@cyclonedx/cyclonedx-library` 10.0.0 → 10.1.0, `@pnpm/config.nerf-dart` ^1 → ^2, `@pnpm/log.group` 3.0.2 → 4.0.1, `@pnpm/util.lex-comparator` ^3 → ^4. - Updated `@zkochan/cmd-shim` to v9.0.6. - Fixed a Windows-only hang where a failed command could take 20–46 seconds to exit. On error, pnpm enumerates descendant processes (via `pidtree`) to terminate them, which on Windows shells out to `wmic`/PowerShell `Get-CimInstance Win32_Process` — a lookup that is extremely slow on some machines. The lookup is now bounded by a short timeout so it can no longer stall the process exit. <!-- 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 --> ### [`v11.6.0`](https://github.com/pnpm/pnpm/releases/tag/v11.6.0): pnpm 11.6 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.5.3...v11.6.0) ##### ⚠️ Security fix — environment variables in a project `.npmrc` (action may be required) Following [GHSA-3qhv-2rgh-x77r](https://github.com/pnpm/pnpm/security/advisories/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`: ```sh # 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 `~/.npmrc` instead of the repo. In **GitHub Actions**, `actions/setup-node` with `registry-url` already writes a user-level `.npmrc`, so `NODE_AUTH_TOKEN` keeps working. For other CI where editing each pipeline is hard, set `PNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc` (or `NPM_CONFIG_USERCONFIG=.npmrc`) in the CI environment to declare the project `.npmrc` trusted. See <https://pnpm.io/npmrc> for full migration details. ##### Minor Changes - `pnpm install` completes without re-resolving when `pnpm-lock.yaml` was deleted but `node_modules` is 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, restores `pnpm-lock.yaml` from 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`](https://github.com/pnpm/pnpm/commit/615c669): Added support for configuring URL-scoped registry settings through `npm_config_//…` and `pnpm_config_//…` environment variables, for example: ```text 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 `.npmrc` but 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))` to `min(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. The `networkConcurrency` setting still overrides the default. ##### Patch Changes - Improved the warning printed when a project `.npmrc` uses 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 `~/.npmrc` or running `pnpm config set "<key>" <value>` — with a link to <https://pnpm.io/npmrc>. The `pnpm config set` example 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 [#&#8203;12324](https://github.com/pnpm/pnpm/issues/12324). - Platform-specific optional dependencies are now skipped even when their `os`/`cpu`/`libc` fields 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 of `supportedArchitectures`. 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 [#&#8203;11702](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.5.3`](https://github.com/pnpm/pnpm/releases/tag/v11.5.3): pnpm 11.5.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.5.2...v11.5.3) ##### ⚠️ Security fix — environment variables in a project `.npmrc` (action may be required) Following [GHSA-3qhv-2rgh-x77r](https://github.com/pnpm/pnpm/security/advisories/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`: ```sh # 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 `~/.npmrc` instead of the repo. In **GitHub Actions**, `actions/setup-node` with `registry-url` already writes a user-level `.npmrc`, so `NODE_AUTH_TOKEN` keeps working. For other CI where editing each pipeline is hard, set `PNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc` (or `NPM_CONFIG_USERCONFIG=.npmrc`) in the CI environment to declare the project `.npmrc` trusted. 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 from `pnpm-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 `packageManagerDependencies` to `pnpm-lock.yaml` when package manager policy is set to `onFail: ignore` or `pmOnFail: ignore` [#&#8203;12228](https://github.com/pnpm/pnpm/issues/12228). - Avoid running dependency-status auto-install when the dependency status is unavailable without a project manifest. - Using the `$` version reference syntax in `overrides` (e.g. `"react": "$react"`) now prints a deprecation warning. The syntax still works, but [catalogs](https://pnpm.io/catalogs) are the recommended way to keep an overridden version in sync with the rest of the workspace. Reference a catalog entry with the `catalog:` protocol instead. - Fixed `pnpm config get globalconfig` to return the global `config.yaml` path again [pnpm/pnpm#11962](https://github.com/pnpm/pnpm/issues/11962). - Fixed bare `--color` so it does not consume the following CLI flag, allowing command shorthands like `--parallel` to expand correctly and forms like `pnpm --color with current <command>` to dispatch the inner command instead of failing with `MISSING_WITH_CURRENT_CMD`. - Fix `pnpm install` ignoring `enableGlobalVirtualStore` toggle by including it in the workspace state settings check [#&#8203;12142](https://github.com/pnpm/pnpm/issues/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`) in `configDependencies` opts in to pnpm's Rust install engine. pnpm now verifies that the installed `pacquet` shim and the host's `@pacquet/<platform>-<arch>` binary carry a valid npm registry signature for their exact `name@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`** — the `packageManager` / `devEngines.packageManager` field makes pnpm download and run a specific pnpm version. pnpm now verifies the registry signature of `pnpm`, `@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. - 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 --check` alternate 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 `bin` names (`""`, `"."`, `".."`, 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 `allowBuilds` entries 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 the `allowBuilds` key. 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.txt` before trusting its integrity hashes. When a repository requests a Node.js runtime (e.g. via `devEngines.runtime` / `useNodeVersion`), the download mirror is repository-configurable through `node-mirror:<channel>`. The integrity of the downloaded binary was only checked against `SHASUMS256.txt` fetched from that same mirror — a circular check that a malicious mirror could satisfy by serving a tampered binary together with a matching `SHASUMS256.txt`. pnpm then executes the binary (for example to run lifecycle scripts). pnpm now fetches `SHASUMS256.txt.sig` and 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 canonical `nodejs/release-keys` list. The musl variants from the hardcoded `unofficial-builds.nodejs.org` mirror 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 --> ### [`v11.5.2`](https://github.com/pnpm/pnpm/releases/tag/v11.5.2): pnpm 11.5.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.5.1...v11.5.2) ##### 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 `tarball` URL points at the artifact the registry's own metadata lists for that `name@version`. Previously a tampered lockfile could pair a trusted `name@version` with 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 with `ERR_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 with `Invalid Version` when the catalog entry for `<pkg>` is a version range (e.g. `^21.2.10`) and `catalogMode` is `strict` or `prefer`. The catalog–version comparison now skips the equality check when either side is a range rather than passing a range to `semver.eq()`, so range specifiers fall through to the existing mismatch handling instead of throwing [#&#8203;11570](https://github.com/pnpm/pnpm/issues/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 multiple `pnpm install` processes 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 the `package.json` completion 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 [#&#8203;12197](https://github.com/pnpm/pnpm/issues/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 `rebuild` pass (`buildProjects`). That pass resolved each package's location from the classic `node_modules/.pnpm/<depPathToFilename>` layout, which does not exist under the global virtual store — so native dependencies (e.g. packages using `node-gyp` / `prebuild-install`) were never built and failed to load at runtime (`Cannot find module .../build/Release/*.node`). `buildProjects` now resolves the global-virtual-store projection directory (`<storeDir>/links/<hash>`, computed with the same graph hash the installer uses) when `enableGlobalVirtualStore` is 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 from `devEngines.runtime` or `pnpm runtime set`) into a catalog when `catalogMode` is `strict` or `prefer`. A `runtime:` dependency round-trips to `devEngines.runtime`, which only recognizes the `runtime:` protocol; cataloging it rewrote the manifest entry to `catalog:`, which broke that round-trip, stranded it in `devDependencies`, and left `devEngines.runtime` untouched. - Skip lockfile `minimumReleaseAge`/`trustPolicy` verification for non-registry tarball protocols (for example `file:`), 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 --> ### [`v11.5.1`](https://github.com/pnpm/pnpm/releases/tag/v11.5.1): pnpm 11.5.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.5.0...v11.5.1) ##### Patch Changes - Improve `pnpm audit` performance 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_agent` for root lifecycle scripts during headless installs. - Preserve the `integrity` field of a remote (non-registry) tarball dependency when its lockfile entry is rebuilt. Re-resolving such a dependency without re-fetching it (for example via `pnpm 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 with `ERR_PNPM_MISSING_TARBALL_INTEGRITY` [#&#8203;12067](https://github.com/pnpm/pnpm/issues/12067). - Normalize a string `repository` field into the `{ type, url }` object form when creating the publish manifest, matching npm's behavior. Some registries (e.g. Gitea/Codeberg) reject a string `repository` with a 500 Internal Server Error during `pnpm publish` [#&#8203;12099](https://github.com/pnpm/pnpm/issues/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-plugin` peer-depends on both `@typescript-eslint/parser` and `typescript`, and `@typescript-eslint/parser` peer-depends on `typescript`), pnpm no longer reuses a hoisted instance of the shared peer that was resolved against a different version [#&#8203;12079](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.5.0`](https://github.com/pnpm/pnpm/releases/tag/v11.5.0): pnpm 11.5 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.4.0...v11.5.0) ##### Minor Changes - Added a new `hoistingLimits` setting for `nodeLinker: hoisted` installs, mirroring yarn's `nmHoistingLimits`. It accepts `none` (the default — hoist as far as possible), `workspaces` (hoist only as far as each workspace package), or `dependencies` (hoist only up to each workspace package's direct dependencies). Originally proposed in [#&#8203;6468](https://github.com/pnpm/pnpm/pull/6468), closing [#&#8203;6457](https://github.com/pnpm/pnpm/issues/6457). - Replaced `enquirer` with `@inquirer/prompts` for all interactive prompts. Fixes the `update -i` scrolling overflow bug where long choice lists were clipped in the terminal [#&#8203;6643](https://github.com/pnpm/pnpm/issues/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 via `usePagination` - `pnpm audit --fix -i`: Same scrolling fix for vulnerability selection - `pnpm approve-builds`: Interactive build approval prompts updated - `pnpm patch`: Version selection and "apply to all" prompts updated - `pnpm patch-remove`: Patch removal selection updated - `pnpm publish`: Branch confirmation prompt updated - `pnpm login`: Credential prompts updated - `pnpm run` / `pnpm exec` (with `verifyDepsBeforeRun=prompt`): Confirmation prompt updated Vim-style `j`/`k` keys still work for up/down navigation in all interactive prompts. **Internal:** The `OtpEnquirer` and `LoginEnquirer` DI 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 `approver` field, 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 [#&#8203;11887](https://github.com/pnpm/pnpm/issues/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 the `findHit` cache instead of running their own `calculateDepPath` are now short-circuited by sibling resolutions at the level where the cycle is detected, so the cached path promises no longer deadlock. [#&#8203;11999](https://github.com/pnpm/pnpm/issues/11999). - Fix `pnpm dist-tag add` and `pnpm dist-tag rm` against npmjs.org failing without `--otp` with `[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 sends `npm-auth-type: web` on dist-tag writes and surfaces the resulting OTP challenge through the existing browser-based 2FA flow (the same `withOtpHandling` helper used by `pnpm 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 `minimumReleaseAgeExclude` handling in npm resolution fast paths so excluded packages do not get pinned to stale versions. Excludes are honored consistently during `publishedBy` metadata selection and cache-mtime shortcuts. - Fix the `integrity` field 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-lockfile` installs fail with `ERR_PNPM_MISSING_TARBALL_INTEGRITY`. [#&#8203;12001](https://github.com/pnpm/pnpm/issues/12001). - Skip dependency re-resolution when `pnpm-lock.yaml` is missing but `node_modules/.pnpm/lock.yaml` exists and still satisfies the manifest. `pnpm install` now reuses the materialized snapshot to regenerate `pnpm-lock.yaml` instead 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 [#&#8203;11993](https://github.com/pnpm/pnpm/issues/11993). `--frozen-lockfile` still refuses to proceed when `pnpm-lock.yaml` is 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 --> ### [`v11.4.0`](https://github.com/pnpm/pnpm/releases/tag/v11.4.0): pnpm 11.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.3.0...v11.4.0) ##### Minor Changes - Treat tarball-integrity mismatches against the lockfile as a hard failure by default. Previously, `pnpm install` (non-frozen) would log `ERR_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 install` now exits with `ERR_PNPM_TARBALL_INTEGRITY` and 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. `--force` and `pnpm update` deliberately 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-lockfile` behavior is unchanged. `--fix-lockfile` keeps its documented purpose (filling in missing lockfile entries) and is also not a bypass. - `pnpm runtime set <name> <version>` now saves the runtime to `devEngines.runtime` by default instead of `engines.runtime`. Pass `--save-prod` (or `-P`) to save it to `engines.runtime` instead [#&#8203;11948](https://github.com/pnpm/pnpm/issues/11948). ##### Patch Changes - Fix a credential disclosure issue where an unscoped `_authToken` (or `_auth`, or `username` + `_password`, or `tokenHelper`) defined in one source — `~/.npmrc`, `~/.config/pnpm/auth.ini`, a workspace `.npmrc`, CLI flags, etc. — would be sent as an `Authorization` header 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 the `registry=` value declared in the same source (or the npmjs default registry if the source declares none). A later layer overriding `registry=` therefore cannot pull an unscoped credential along, because it is already pinned to the URL its author intended. `ca`/`cafile` are 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 the `defaultRegistry` parameter from `createGetAuthHeaderByURI` and `getAuthHeadersFromCreds`. Now that credentials are URL-scoped at load time, the merged `configByUri` never contains the empty-string "default registry" placeholder slot, so re-keying it onto the merged default registry is no longer needed. - Fix `pnpm deploy` crashing with `ENOENT: ... lstat '<deployDir>/node_modules'` when `configDependencies` declares pacquet (`pacquet` or `@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 `commit` field is not a 40-character hexadecimal SHA before invoking `git`. A malicious lockfile could otherwise smuggle a value such as `--upload-pack=<command>` through `git 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 `EMFILE` errors. - Reject patch files whose `diff --git` headers reference paths outside the patched package directory. Previously a malicious `.patch` file added via a pull request could write, delete, or rename arbitrary files reachable by the user running `pnpm install`. - Improve the log message that pnpm prints after auto-adding entries to `minimumReleaseAgeExclude` when `minimumReleaseAge` is set without `minimumReleaseAgeStrict`. The message previously referred to the internal "loose mode" terminology, which wasn't searchable in the docs; it now tells the user to set `minimumReleaseAgeStrict` to `true` if they want these updates gated behind a prompt instead [#&#8203;11747](https://github.com/pnpm/pnpm/issues/11747). - Reject dependency aliases that contain path-traversal segments (such as `@x/../../../../../.git/hooks`) when reading them from a package manifest or symlinking them into `node_modules`. A malicious registry package could otherwise use a transitive dependency key to make `pnpm install` create symlinks at attacker-chosen paths outside the intended `node_modules` directory. - Reject `pnpm-lock.yaml` entries whose remote tarball `resolution:` block is missing the `integrity` field. 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 strips `integrity:`) 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 with `ERR_PNPM_MISSING_TARBALL_INTEGRITY`. Git-hosted tarballs (`gitHosted: true` or a URL on codeload.github.com / bitbucket.org / gitlab.com) and `file:` tarballs are exempt — the commit SHA in a git-host URL and the user-controlled local path already anchor the bytes. - Validate `devEngines.runtime` and `engines.runtime` version ranges for `node`, `deno`, and `bun` when `onFail` is set to `error` or `warn`. Previously these settings only had an effect with `onFail: 'download'` — the `error` and `warn` modes silently did nothing [#&#8203;11818](https://github.com/pnpm/pnpm/issues/11818). Violations now throw `ERR_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 --> ### [`v11.3.0`](https://github.com/pnpm/pnpm/releases/tag/v11.3.0): pnpm 11.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.2.2...v11.3.0) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Minor Changes - Added `pnpm stage` with `publish`, `list`, `view`, `approve`, `reject`, and `download` subcommands for npm staged publishing. - Added a new setting `trustLockfile`. When `true`, `pnpm install` skips the supply-chain verification pass that re-applies `minimumReleaseAge` / `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 to `false`; verification stays on by default. Set in `pnpm-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 (`~4k` lockfile entries with `minimumReleaseAge` + `trustPolicy: no-downgrade` enabled) 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-level `modified` field and the set of currently-listed version names. Fixes [#&#8203;11860](https://github.com/pnpm/pnpm/issues/11860). - Implemented `pnpm pkg` command natively, following `npm pkg` standards. - Implemented `pnpm repo` command natively, following `npm repo` standards. - Implemented `pnpm set-script` (alias `ss`) natively. Adds or updates an entry in the `scripts` field of the project manifest, supporting `package.json`, `package.json5`, and `package.yaml` formats. - Add a `skip-manifest-obfuscation` option for `pnpm pack` and `pnpm publish`. When enabled, the original `packageManager` field and publish lifecycle scripts are kept in the packed/published manifest instead of being stripped. The pnpm-specific `pnpm` field continues to be omitted. ##### Patch Changes - Fixed `pnpm dlx` failing with `ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND` when the installed package's CAS slot is missing its `package.json`. Observed in the wild for `pnpm dlx node@runtime:<version>` when the GVS slot was populated without the synthesized manifest runtime archives need (they don't ship a `package.json` of 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, so `dlx` now falls back to the scopeless package name when the slot's manifest is unreadable — for single-bin packages (the dlx common case, including every `runtime:` spec) this matches what `manifest.bin` would have named. Multi-bin packages already require `--package=<spec> <bin>` to disambiguate and don't enter this code path. - Fixed non-determinism in `pnpm dedupe` and `pnpm install` when a dependency graph contains packages with transitive peer dependencies on each other (e.g. `@aws-sdk/client-sts` and `@aws-sdk/client-sso-oidc`) and `auto-install-peers` is enabled. The lockfile no longer flips between two equally-valid forms across consecutive runs. The root cause was that `resolveDependencies` pushed onto its `pkgAddresses` / `postponedResolutionsQueue` arrays from inside `Promise.all`-spawned callbacks, so completion-order timing leaked into the array order and downstream cyclic-peer suffix assignment. Fixes [#&#8203;8155](https://github.com/pnpm/pnpm/issues/8155). - Fixed a regression introduced by [#&#8203;11711](https://github.com/pnpm/pnpm/pull/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 or `pnpm/test-git-fetch#sha`) was silently dropped from the manifest update and from `pendingBuilds`. The alias-keyed lookup added in that PR couldn't find a `wantedDependency` whose `alias` was `undefined` at parse time but resolved to a package name only after fetching, so the entry never made it into `specsToUpsert`. Restored the original index-based pairing between `directDependencies` and `wantedDependencies`; the catalog-protocol preservation that PR was originally fixing is unaffected because it's driven by `rdd.catalogLookup.userSpecifiedBareSpecifier`, not by the lookup. Fixes the three `rebuilds dependencies` / `rebuilds specific dependencies` / `rebuild with pending option` failures in `building/commands/test/build/index.ts`. - Fixed `pnpm add --config` leaving orphan entries in `pnpm-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 --> ### [`v11.2.2`](https://github.com/pnpm/pnpm/releases/tag/v11.2.2): pnpm 11.2.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.2.1...v11.2.2) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Minor Changes - **Experimental:** Adding [`@pnpm/pacquet`](https://npmx.dev/package/@&#8203;pnpm/pacquet) (the Rust port of pnpm) to `configDependencies` in `pnpm-workspace.yaml` now delegates the materialization phase of `pnpm install` to 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 [#&#8203;11723](https://github.com/pnpm/pnpm/issues/11723). To configure pacquet in a project, run: ``` pnpm add @pnpm/pacquet --config ``` You'll see changes in `pnpm-workspace.yaml` and `pnpm-lock.yaml` that 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 to `pnpm install` (e.g. `--no-runtime`, `--prod`, `--dev`, `--no-optional`, `--node-linker`, `--cpu`/`--os`/`--libc`, `--offline`, `--prefer-offline`) are now forwarded to pacquet's `install` subcommand verbatim. Previously pacquet was invoked with a fixed argument list, so flags like `--no-runtime` were silently dropped. Flag forwarding is gated on the command being `install`/`i`; `add`, `update`, and `dedupe` still don't forward (their flag surface doesn't line up with pacquet's `install`). - Fixed `pnpm up` (and `pnpm add` / `pnpm remove`) failing with `pacquet_package_manager::outdated_lockfile` when pacquet is declared in `configDependencies`. pnpm now passes `--ignore-manifest-check` to pacquet so its `--frozen-lockfile` check doesn't fire against the (pre-mutation) `package.json` pnpm hasn't written yet [#&#8203;11797](https://github.com/pnpm/pnpm/issues/11797). Requires a pacquet release that supports the flag — bump `PACQUET_VERSION` in 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 --> ### [`v11.2.1`](https://github.com/pnpm/pnpm/releases/tag/v11.2.1): pnpm 11.2.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.2.0...v11.2.1) ##### Minor Changes - **Experimental:** Adding [`@pnpm/pacquet`](https://npmx.dev/package/@&#8203;pnpm/pacquet) (the Rust port of pnpm) to `configDependencies` in `pnpm-workspace.yaml` now delegates the materialization phase of `pnpm install` to 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 [#&#8203;11723](https://github.com/pnpm/pnpm/issues/11723). To configure pacquet in a project, run: ``` pnpm add @pnpm/pacquet --config ``` You'll see changes in `pnpm-workspace.yaml` and `pnpm-lock.yaml` that 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: true` in the env lockfile, matching how optional dependencies are recorded elsewhere in `pnpm-lock.yaml`. Previously, snapshots for the platform-specific subdeps pulled in via a config dep's `optionalDependencies` were 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 `pickRegistryForPackage` returning the wrong registry for an unscoped `npm:` alias under a scoped local name. A manifest entry like `"@private/foo": "npm:lodash@^1"` was routing the `lodash` fetch through `registries["@private"]`, even though `lodash` is unscoped and doesn't live on that registry. The npm-alias branch now returns the alias target's own scope (or `null` for an unscoped target, falling through to `registries.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 --> ### [`v11.2.0`](https://github.com/pnpm/pnpm/releases/tag/v11.2.0): pnpm 11.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.1.3...v11.2.0) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Minor Changes - **Experimental:** Adding [`@pnpm/pacquet`](https://npmx.dev/package/@&#8203;pnpm/pacquet) (the Rust port of pnpm) to `configDependencies` in `pnpm-workspace.yaml` now delegates the materialization phase of `pnpm install` to 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 [#&#8203;11723](https://github.com/pnpm/pnpm/issues/11723). To configure pacquet in a project, run: ``` pnpm add @pnpm/pacquet --config ``` You'll see changes in `pnpm-workspace.yaml` and `pnpm-lock.yaml` that should be committed. If you experience any issues with pacquet, please let us know by mentioning this in the GitHub issue you create. - `configDependencies` now resolve and install one level of `optionalDependencies` declared by the config dependency, with `os`/`cpu`/`libc` platform filtering applied at install time. This unlocks the esbuild/swc-style pattern where a package ships platform-specific binaries via `optionalDependencies` — a config dependency can now do the same and have the matching binary symlinked next to it in the global virtual store, so `require('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 `optionalDependencies` must 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. Previously `pnpm login --scope foo` errored with `Unknown option: 'scope'` despite the flag being listed in the online documentation [#&#8203;11716](https://github.com/pnpm/pnpm/issues/11716). - `pnpm outdated` and `pnpm update --interactive` now 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 `.npmrc` being read from the wrong directory when pnpm is invoked from a different cwd (e.g. `pnpm --dir <project> install` from a CI wrapper or monorepo script). The path is now resolved against the directory of the `.npmrc` that declared it, not `process.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 [#&#8203;11624](https://github.com/pnpm/pnpm/issues/11624). - Fix `config.registry` getting a trailing slash appended when `registry` is set in `.npmrc` and no `registries.default` is provided by `pnpm-workspace.yaml`. The sync from `registries.default` to `config.registry` introduced in [#&#8203;11744](https://github.com/pnpm/pnpm/issues/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: true` when the lockfile has been pruned (e.g. by `turbo prune --docker`): - `Cannot use 'in' operator to search for 'directory' in undefined`: a peer-dependency-variant injected snapshot inherits its `resolution` from the base `packages:` entry; when a pruner drops that base entry the readers crash. `convertToLockfileObject` now reconstructs the directory resolution from the `file:` depPath at load time — a single normalization point, so every reader sees a fully-formed snapshot. - `ERR_PNPM_ENOENT` on `node_modules/.bin/<tool>`: after `prepare`/`postinstall`, `runLifecycleHooksConcurrently` re-imported each injected workspace package; the `scanDir`-into-`filesMap` workaround fed target-internal paths to the importer, which the `makeEmptyDir` fast path ([#&#8203;11088](https://github.com/pnpm/pnpm/issues/11088)) then wiped. Drop the workaround and pass `keepModulesDir: true` so the importer preserves the target's existing `node_modules` (bin links + transitive deps) and source files keep their hardlinks. - Fixed `pnpm login` and `pnpm logout` ignoring `registries.default` from `pnpm-workspace.yaml` [#&#8203;10099](https://github.com/pnpm/pnpm/issues/10099). - Fix the `minimumReleaseAge` (publishedBy) maturity shortcut to be inclusive at the cutoff. Previously, abbreviated metadata whose `modified` field equalled the cutoff fell off the fast path and triggered a full-metadata re-fetch (or a `MISSING_TIME` error when full metadata wasn't permitted). Since `modified` is an upper bound on every version's publish time, `modified == publishedBy` already implies every version passes the per-version `<=` filter in `filterPkgMetadataByPublishDate`, so the shortcut now accepts the boundary case directly. Strictly `>` (was `>=`) at the rejection branch. - Honor `publishConfig.access` when 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 --> ### [`v11.1.3`](https://github.com/pnpm/pnpm/releases/tag/v11.1.3): pnpm 11.1.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.1.2...v11.1.3) ##### Patch Changes - `pnpm install` now re-validates `pnpm-lock.yaml` entries against the active `minimumReleaseAge` and `trustPolicy: '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 with `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`, `ERR_PNPM_TRUST_DOWNGRADE`, or the generic `ERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATION` when both policies trip in the same batch; `minimumReleaseAgeExclude` and `trustPolicyExclude` are 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 `minimumReleaseAge` keeps its built-in 24-hour value — auto-adds the immature picks to `minimumReleaseAgeExclude` in `pnpm-workspace.yaml` and 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 `minimumReleaseAgeExclude` and the install continues; declining aborts before the lockfile, `package.json`, or `node_modules` is touched. - **Strict mode** in CI (or any non-TTY context) aborts with `ERR_PNPM_NO_MATURE_MATCHING_VERSION` listing every offending entry, instead of failing on the first one the resolver hit. `minimumReleaseAgeStrict` auto-enables whenever the user explicitly sets `minimumReleaseAge` (CLI flag, env var, global `config.yaml`, or `pnpm-workspace.yaml`); set `minimumReleaseAgeStrict: false` to keep loose-mode auto-collect even with an explicit `minimumReleaseAge` value. Closes [#&#8203;10438](https://github.com/pnpm/pnpm/issues/10438), [#&#8203;10488](https://github.com/pnpm/pnpm/issues/10488), [#&#8203;11687](https://github.com/pnpm/pnpm/issues/11687). - Allow redundant trailing base64 padding in `.npmrc` auth values and report invalid auth base64 with a pnpm error. - Make `pnpm self-update` respect `minimumReleaseAge` (and `minimumReleaseAgeExclude`) when resolving which pnpm version to install. When the `latest` dist-tag points to a version newer than the configured age threshold, `self-update` now selects the newest mature version instead unless excluded by `minimumReleaseAgeExclude`. Also makes `dlx` and `outdated` surface invalid `minimumReleaseAgeExclude` patterns under the same `ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE` error code already used by `install`, instead of leaking the internal `ERR_PNPM_INVALID_VERSION_UNION` / `ERR_PNPM_NAME_PATTERN_IN_VERSION_UNION` codes. - Global installs respect global config build policy (e.g., `dangerouslyAllowAllBuilds` from config.yaml) when GVS is enabled [#&#8203;9249](https://github.com/pnpm/pnpm/issues/9249). The global virtual-store (GVS) default `allowBuilds = {}` was applied before workspace manifest settings were read and before global config values (stripped by `extractAndRemoveDependencyBuildOptions`) were re-applied via `globalDepsBuildConfig`. This caused `hasDependencyBuildOptions` to return `true` (because `{}` is not null), blocking restoration of global config values like `dangerouslyAllowAllBuilds`. 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 `globalDepsBuildConfig` re-application, so that: 1. Workspace manifest `allowBuilds` takes precedence (if present) 2. Global config `dangerouslyAllowAllBuilds` is properly restored (if set and no workspace policy exists) 3. Empty `{}` is only applied as a last resort when no policy is configured anywhere - Honor `--silent` when `verifyDepsBeforeRun: install` auto-installs dependencies before `pnpm run` or `pnpm exec`, preventing install output from being written to stdout [#&#8203;11636](https://github.com/pnpm/pnpm/issues/11636). - Fix lockfile parsing failures when `pnpm-lock.yaml` contains CRLF line endings and multiple YAML documents [#&#8203;11612](https://github.com/pnpm/pnpm/issues/11612). - Anchor the side-effects-cache key and global-virtual-store hash to the project's script-runner Node — `engines.runtime` pin when present, shell `node` otherwise — 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 from `process.version` — the Node that runs pnpm itself. That was wrong in two situations: 1. **`@pnpm/exe` SEA bundle.** The bundle has its own embedded Node, not the `node` on the user's `PATH` that 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 shell `node`. 2. **`engines.runtime` / `devEngines.runtime` pin.** When a project pins a Node version via `devEngines.runtime` (pnpm v11+), pnpm downloads that Node into `node_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-version` now exports `engineName(nodeVersion?)`. Resolves the version in this order: explicit override → `getSystemNodeVersion()` (which already prefers `node --version` over `process.version` in SEA contexts) → `process.version`. - `@pnpm/deps.graph-hasher` now exports `findRuntimeNodeVersion(snapshotKeys)` — scans an iterable of lockfile snapshot keys for a `node@runtime:<version>` entry and returns its bare version string. `calcDepState` and `calcGraphNodeHash`/`iterateHashedGraphNodes` accept a `nodeVersion?` (in the options bag for the first, as a trailing parameter / ctx field for the others), forwarded to `engineName()`. The default (no override) preserves the pre-change behaviour. The legacy `ENGINE_NAME` constant in `@pnpm/constants` is 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 via `findRuntimeNodeVersion(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-published `pnpm` package, and any other pnpm-compatible tool already produce. - **Projects with a `devEngines.runtime` pin**: 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.runtime` into `dependencies.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/linker` already does on a per-package basis: - `@pnpm/deps.graph-hasher` adds `readSnapshotRuntimePin(children)` — reads the `node` entry from one snapshot's graph children and extracts the version from a `node@runtime:` value. Pairs with the existing `findRuntimeNodeVersion(snapshotKeys)` install-wide fallback (also now exported from `@pnpm/deps.graph-hasher` rather than `@pnpm/engine.runtime.system-node-version`, where it was a poor fit — `system-node-version` is about probing the host Node, not parsing lockfile-derived strings). - `calcDepState` and `calcGraphNodeHash` consult `readSnapshotRuntimePin(graph[depPath].children)` first and only fall back to the install-wide `nodeVersion` parameter when the snapshot doesn't pin its own Node. Pacquet mirrors the same precedence at the `calc_graph_node_hash` call site in `package-manager/src/virtual_store_layout.rs` — a new `find_own_runtime_node_major(snapshot)` helper reads each snapshot's `dependencies` for a `node` entry with `Prefix::Runtime` and overrides the install-wide engine when present. On upgrade, snapshots of dependencies that declare their own `engines.runtime` re-hash under that dep's pinned Node instead of the install-wide value. The old slots become prune-eligible. Closes [#&#8203;11690](https://github.com/pnpm/pnpm/issues/11690). - Fixed `pnpm publish` failing with a 404 when authentication relied on OIDC trusted publishing alongside an `.npmrc` written by `actions/setup-node` (`_authToken=${NODE_AUTH_TOKEN}`) without `NODE_AUTH_TOKEN` being 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 [#&#8203;11513](https://github.com/pnpm/pnpm/issues/11513). - Fix `devEngines.packageManager` (singular form, without `onFail`) defaulting to `onFail: "error"` instead of the documented `pmOnFail: "download"`. As a result, a project that pinned a different pnpm version via `devEngines.packageManager` and ran `pnpm install` from a mismatched pnpm version failed with a hard error, even though the migration table from `managePackageManagerVersions: true` to `pmOnFail: download (default)` promises the install would auto-download the wanted version [#&#8203;11676](https://github.com/pnpm/pnpm/issues/11676). The array form of `devEngines.packageManager` keeps its existing per-element defaults (`error` for the last entry, `ignore` for the rest), since those reflect explicit prioritization by the user. Explicit `onFail` values continue to win. - Fix `devEngines.packageManager` not writing `packageManagerDependencies` to `pnpm-lock.yaml` when the lockfile lacks an env-doc entry. Previously the lockfile sync skipped resolution unless an existing `packageManagerDependencies.pnpm` entry needed refreshing, so a fresh install without `onFail: "download"` left the resolved pnpm version unrecorded — contradicting the documented behavior that the resolved version is stored in `pnpm-lock.yaml` [#&#8203;11674](https://github.com/pnpm/pnpm/issues/11674). - Warn when `package.json` contains a legacy `pnpm` field with settings pnpm no longer reads from `package.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 [#&#8203;11677](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.1.2`](https://github.com/pnpm/pnpm/releases/tag/v11.1.2): pnpm 11.1.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.1.1...v11.1.2) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Patch Changes - Strip `sec-fetch-*` headers from outgoing HTTP requests. These headers are automatically added by undici's `fetch()` 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 [#&#8203;11572](https://github.com/pnpm/pnpm/issues/11572). - Fix `minimumReleaseAge` handling for cached abbreviated metadata. The version-spec cache fast path no longer rethrows `ERR_PNPM_MISSING_TIME` under `strictPublishedByCheck`; 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 with `fullMetadata: true` if `minimumReleaseAge` is 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 [#&#8203;11619](https://github.com/pnpm/pnpm/issues/11619). - Fix `pnpm upgrade --interactive --latest -r` not respecting named catalog groups. Previously, upgrading a dependency using a named catalog (e.g. `"catalog:foo"`) would incorrectly rewrite `package.json` to `"catalog:"` and place the updated version in the default catalog instead of the named one [#&#8203;10115](https://github.com/pnpm/pnpm/issues/10115). - Fixed `optimisticRepeatInstall` skipping `pnpm-lock.yaml` merge conflict resolution when the existing `node_modules` state appears up to date. - Fix `minimumReleaseAge` / `resolutionMode: time-based` installs failing on lockfiles whose `time:` block is missing entries. The npm-resolver's peek-from-store fast path now surfaces `publishedAt` from 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 --> ### [`v11.1.1`](https://github.com/pnpm/pnpm/releases/tag/v11.1.1): pnpm 11.1.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.1.0...v11.1.1) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Patch Changes - Skip installability validation when scanning workspace projects in `checkDepsStatus` (run by `verifyDepsBeforeRun`). Previously the status check called `findWorkspaceProjects`, which validates each project's `engines` and `os`/`cpu`/`libc` and warns about useless fields in non-root manifests — work that the install pipeline already performs. With no `nodeVersion` threaded through, the engine check also fell back to the system Node from `PATH` and emitted spurious "Unsupported engine" warnings before scripts ran. Status-only callers now use `findWorkspaceProjectsNoCheck`; install paths continue to validate. - Fixed `pnpm add <alias>:@scope/pkg` for [named registries](https://github.com/pnpm/pnpm/pull/11324). The local resolver was claiming any specifier containing `/` as a local directory, so `pnpm add bit:@teambit/bit` (with `bit` configured under `namedRegistries`) installed a bogus link to `bit:@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-shim` to 9.0.3. The sh shim it writes for `.cmd` / `.bat` targets now escapes the `/C` switch as `//C`, so it survives the path translation Git Bash applies when launching `cmd.exe`. Without this, a bare `/C` was rewritten to `C:\` 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](https://github.com/pnpm/cmd-shim/pull/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 --> ### [`v11.1.0`](https://github.com/pnpm/pnpm/releases/tag/v11.1.0): pnpm 11.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.9...v11.1.0) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Minor Changes - Added `pnpm audit signatures` to verify ECDSA registry signatures for installed packages against keys from `/-/npm/v1/keys` [#&#8203;7909](https://github.com/pnpm/pnpm/issues/7909). Scoped registries are respected, and registries without signing keys are skipped. - Added support for installing packages from the [GitHub Packages npm registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-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](https://docs.vlt.sh/cli/registries). Authentication is picked up from the existing per-URL `.npmrc` entries (e.g. `//npm.pkg.github.com/:_authToken=...`), so no separate auth mechanism is required. Additional aliases — or an override for the built-in `gh` alias, for GitHub Enterprise Server — can be configured under `namedRegistries` in `pnpm-workspace.yaml`: ```yaml namedRegistries: gh: https://npm.pkg.github.example.com/ work: https://npm.work.example.com/ ``` With this, `work:@corp/lib@^2.0.0` resolves against `https://npm.work.example.com/`. [#&#8203;11324](https://github.com/pnpm/pnpm/issues/11324). - Allow setting sbom spec version using `--sbom-spec-version` [#&#8203;11389](https://github.com/pnpm/pnpm/pull/11389). - Add `--no-runtime` flag (config: `runtime=false`) to skip installing runtime entries (e.g. Node.js downloaded via `devEngines.runtime`) without modifying the lockfile. The lockfile keeps the runtime entry so frozen-lockfile validation still passes; only the runtime fetch and `.bin` linking are skipped. Useful in CI matrices where the runtime is provisioned externally (e.g. via `pnpm runtime -g set node <version>`) before `pnpm install` runs. - Added the `pnpm bugs` command that opens a package's bug tracker URL in the browser. With no arguments, it reads the current project's `package.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>/issues` when the `bugs` field is missing [#&#8203;11279](https://github.com/pnpm/pnpm/pull/11279). - Added `pnpm owner` command to manage package owners on the registry. ##### Patch Changes - Added "published X ago by Y" information to the `pnpm view` command output, similar to `npm view`. This is useful when comparing against `minimumReleaseAge`. For example, `pnpm view pnpm` now shows: ``` published 17 hours ago by GitHub Actions ``` - `pnpm publish` now honors the configured HTTP/HTTPS proxy (including `https_proxy`/`http_proxy`/`no_proxy` environment variables) when polling the registry's `doneUrl` during the web-based authentication flow. Previously the poll bypassed the proxy, causing the registry to respond `403` from a different source IP and the login to never complete [#&#8203;11561](https://github.com/pnpm/pnpm/issues/11561). - `pnpm add -g` now 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 bar` installs `foo` and `bar` as two independent globals — removing one does not affect the other. - `pnpm add -g foo,bar qar` bundles `foo` and `bar` into a single isolated install while `qar` is installed on its own. Related: [#&#8203;11587](https://github.com/pnpm/pnpm/issues/11587). - `pnpm runtime set <name> <version>` no longer fails in the root of a multi-package workspace with the `ADDING_TO_ROOT` error. Installing the workspace root is a valid target for a runtime, so the command now bypasses that safety check. - Fix `pnpm --version` hanging for the lifetime of the worker pool after the version was printed. `main.ts`'s `--version` short-circuit returned before reaching the command-handler `finally` that calls `finishWorkers()`, so the worker pool that `switchCliVersion` had spawned during integrity resolution stayed alive and held the Node event loop open. The CLI entry now runs `finishWorkers()` from its own `finally`, so every exit path tears the pool down. Repro: `pnpm --version` in a workspace whose `devEngines.packageManager` version already matches the running pnpm + `onFail: "download"`. `switchCliVersion` resolves 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 --> ### [`v11.0.9`](https://github.com/pnpm/pnpm/releases/tag/v11.0.9): pnpm 11.0.9 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.8...v11.0.9) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Patch Changes - Fixed installation of GitLab-hosted dependencies. pnpm now downloads the tarball from `https://gitlab.com/<user>/<project>/-/archive/<sha>/<project>-<sha>.tar.gz` instead of the GitLab API endpoint that contained an encoded slash (`%2F`) between user and project. The encoded slash both triggered `406 Not Acceptable` responses from GitLab and produced virtual store directory names that Node refused to import (`ERR_INVALID_MODULE_SPECIFIER`) [#&#8203;11533](https://github.com/pnpm/pnpm/issues/11533). - Honor `NPM_CONFIG_USERCONFIG` (and its lowercase `npm_config_userconfig` form) 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 notably `actions/setup-node`, which writes registry credentials to `${runner.temp}/.npmrc` and exports `NPM_CONFIG_USERCONFIG` to reference it. Without this, GitHub Actions workflows using `actions/setup-node` to authenticate to private registries broke after upgrading to pnpm v11. PNPM-prefixed env vars and `npmrcAuthFile` from the global `config.yaml` continue to take precedence [#&#8203;11539](https://github.com/pnpm/pnpm/issues/11539). - Fix `pnpm pack` not bundling dependencies listed in `bundleDependencies` (or `bundledDependencies`). 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 — `bundleDependencies` were silently dropped from the tarball [#&#8203;11519](https://github.com/pnpm/pnpm/issues/11519). - Fixed the pnpm CLI crashing with a confusing `SyntaxError: Invalid regular expression flags` instead of printing a clear "requires Node.js v22.13" error when launched on an unsupported Node.js version. The Node.js version check in `bin/pnpm.mjs` was effectively dead code because the static `import` of the bundled `dist/pnpm.mjs` was hoisted by the ES module loader and parsed before the check could run [#&#8203;11546](https://github.com/pnpm/pnpm/issues/11546). - Fixed `pnpm --prefix=<dir> install` overwriting the existing `pnpm-workspace.yaml` in `<dir>` with `set this to true or false` placeholders. The renamed `--prefix` option (which maps to `dir`) was not honored when locating the workspace root, so the workspace manifest's `allowBuilds` settings were not loaded into config and got clobbered when ignored builds were auto-populated [#&#8203;11535](https://github.com/pnpm/pnpm/issues/11535). - Fixed `pnpm publish --provenance` failing 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 [#&#8203;11518](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.0.8`](https://github.com/pnpm/pnpm/releases/tag/v11.0.8): pnpm 11.0.8 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.7...v11.0.8) > See full [v11.0.0 changelog](https://github.com/pnpm/pnpm/releases/tag/v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### Patch Changes - Restored the heuristic that preserves tarball URLs in `pnpm-lock.yaml` when they cannot be derived from name+version+registry, even with the default `lockfileIncludeTarballUrl: false`. Without this, `pnpm install --frozen-lockfile` from an empty store fails with `ERR_PNPM_FETCH_404` for 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: true` continues to force the URL into the lockfile for every package [#&#8203;11276](https://github.com/pnpm/pnpm/issues/11276). - Run `preversion`, `version`, and `postversion` lifecycle scripts for `pnpm version`. - Fixed `ERR_PNPM_BAD_TARBALL_SIZE` when a registry serves tarballs with an end-to-end `Content-Encoding` (e.g. `gzip`). Tarballs are already compressed, so the fetcher now requests them with `Accept-Encoding: identity` (matching pnpm v10's effective behavior) and, as defense in depth against misbehaving servers, no longer enforces the strict `Content-Length` check when the response declares a `Content-Encoding` — `Content-Length` in that case refers to the encoded payload, not the decoded bytes the fetch implementation yields [#&#8203;11506](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.0.7`](https://github.com/pnpm/pnpm/releases/tag/v11.0.7): pnpm 11.0.7 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.6...v11.0.7) ##### Patch Changes - Restore the execute bit on the `node-gyp` shims packed inside `@pnpm/exe` (`dist/node-gyp-bin/node-gyp`, `dist/node-gyp-bin/node-gyp.cmd`, and `dist/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 invoked `node-gyp rebuild` with `sh: 1: node-gyp: Permission denied` [#&#8203;11483](https://github.com/pnpm/pnpm/issues/11483). - Fixed the `pn`, `pnpx`, and `pnx` aliases failing in Git Bash / MSYS2 on Windows when pnpm was installed via `@pnpm/exe` (or after `pnpm self-update`) [#&#8203;11486](https://github.com/pnpm/pnpm/issues/11486). Running `pnpx` (or `pnx`) printed the cmd.exe banner and dropped the user into an interactive command prompt instead of running `pnpm dlx`. The `bin` field rewrite on Windows was pointing those aliases at `.cmd` files; cmd-shim's Bash shim for a `.cmd` target wraps it in `exec cmd /C ...`, and MSYS2 mangles `/C` into a Windows path before cmd.exe sees it. The aliases are now `.exe` hardlinks of the SEA binary, which detects which name it was launched as via `process.execPath` and prepends `dlx` for `pnpx` / `pnx`. - Fix `pnpm install` recreating `node_modules` after `pnpm fetch`. `pnpm fetch` records empty `hoistPattern` and `publicHoistPattern` in `.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 with `virtualStoreOnly: true` so the next install skips the hoist-pattern comparison and completes the missing post-import linking in place [#&#8203;11488](https://github.com/pnpm/pnpm/issues/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: true` field 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 via `pnpm config set --location global`) instead of being restricted to `pnpm-workspace.yaml`: `agent`, `globalVirtualStoreDir`, `initPackageManager`, `initType`, `registrySupportsTimeField`, `scriptShell`, `shellEmulator`, `sideEffectsCache`, `sideEffectsCacheReadonly`, `stateDir`, `strictDepBuilds`, `trustPolicy`, `trustPolicyExclude`, `trustPolicyIgnoreAfter`, `updateNotifier`, `useStderr`, `verifyDepsBeforeRun`, `verifyStoreIntegrity`, `virtualStoreDir`, `virtualStoreDirMaxLength` [#&#8203;11474](https://github.com/pnpm/pnpm/issues/11474). - Make trusted publishing (OIDC) take precedence over a configured static `_authToken` in `pnpm 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_TOKEN` env 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's `CIRCLE_OIDC_TOKEN_V2`, Buildkite, etc.) can forward its token via `NPM_ID_TOKEN` and 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 `--help` or `--version`. Previously the CLI argument parser short-circuited those flags before universal options were preserved, so `pnpm audit --pm-on-fail=ignore --help` and `pnpm --pm-on-fail=ignore --version` reported the strict packageManager mismatch instead of running the requested action [#&#8203;11487](https://github.com/pnpm/pnpm/issues/11487). - Fix a regression where `pnpm --recursive --filter '!<pkg>' run/exec/test/add` would include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative `--filter` arguments are provided, matching the [documented behavior](https://pnpm.io/cli/recursive). To include the root, pass `--include-workspace-root` [#&#8203;11341](https://github.com/pnpm/pnpm/issues/11341). - Restore npm-CLI-compatible `--json` stdout output for `pnpm publish` ([#&#8203;11476](https://github.com/pnpm/pnpm/issues/11476)). pnpm 11 reimplemented publish natively ([#&#8203;10591](https://github.com/pnpm/pnpm/pull/10591)) and inadvertently dropped the per-package JSON object that pnpm 10 emitted transitively via the npm CLI, silently breaking downstream tooling — most notably `nx release publish`, which parses stdout JSON to confirm success ([nrwl/nx#35575](https://github.com/nrwl/nx/issues/35575)). On success, the output is now: - `pnpm publish --json` → single object `{ id, name, version, size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled }`, mirroring `npm publish --json`. - `pnpm publish -r --json` → array of those objects, mirroring `pnpm pack --json`'s shape choice. - `pnpm publish -r --report-summary` → existing `pnpm-publish-summary.json` envelope `{ publishedPackages: [...] }` is preserved, but each entry is upgraded to the same per-package shape (additive — `name` and `version` are still present). - `pnpm config get @<scope>:registry` now reports the same URL that `pnpm publish` and the resolvers actually use. Previously, `config get` only consulted `.npmrc`, while `publish`/install used the merged map that includes `pnpm-workspace.yaml`'s `registries` block — so the two could diverge silently and a publish could go to the wrong registry [#&#8203;11492](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.0.6`](https://github.com/pnpm/pnpm/releases/tag/v11.0.6): pnpm 11.0.6 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.5...v11.0.6) ##### Patch Changes - Fix `pnpm_config_npmrc_auth_file` and `pnpm_config_userconfig` env vars not actually loading the custom `.npmrc`. The env vars were parsed and assigned to the resolved config, but only after `loadNpmrcConfig` had 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 `.npmrc` is loaded [#&#8203;11465](https://github.com/pnpm/pnpm/issues/11465). - Preserve the original key order in `pnpm-workspace.yaml` when updating it. Existing keys keep their position, and new keys are inserted in alphabetical position when the existing keys are already sorted (with a leading `packages` key allowed) or appended at the end otherwise. - Fixed `pnpm self-update` on installations originally set up by pnpm v10. v10 added `PNPM_HOME` directly to PATH and wrote a `pnpm` bootstrap shim there. v11 setup writes shims under `PNPM_HOME/bin` instead, so when a v10 user upgrades to v11 the legacy shim at `PNPM_HOME` keeps pointing into the old `.tools/<version>` install — `pnpm --version` continues to report the pre-update version even though the new version was installed under `global/v11`. Self-update now detects this layout, refreshes the legacy shims so the upgrade actually takes effect, and prints a hint suggesting `pnpm setup` to migrate PATH to the v11 layout. [#&#8203;11464](https://github.com/pnpm/pnpm/issues/11464). - Print a warning when settings that are not allowed in the global config file (e.g. `nodeLinker`, `hoistPattern`) are present in `config.yaml` and 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-level `pnpm-workspace.yaml`, or sharing them across projects via [config dependencies](https://pnpm.io/11.x/config-dependencies). - Throw a pnpm error when `overrides` has an invalid shape or contains a non-string value. - Validate all `readPackage` dependency map fields, including `devDependencies`, and reject falsy non-object invalid values instead of silently accepting them. - Prevent crashes during `pnpm config`, `pnpm set`, and `pnpm get` by tolerating `configDependencies` install failures. For these commands, a failure to install `configDependencies` (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 [#&#8203;10684](https://github.com/pnpm/pnpm/issues/10684). - Treat `allowBuilds` as an install-state input and clear previously ignored builds when they are explicitly disallowed. - Fixes [#&#8203;10594](https://github.com/pnpm/pnpm/issues/10594), catalogs not being read from the workspace when using the `catalog:` protocol with the `pnpm dlx` / `pnpx` command, resulting in a catalog entry not found error. - Accept `PNPM_CONFIG_*` (uppercase) environment variables in addition to `pnpm_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 [#&#8203;11465](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.0.5`](https://github.com/pnpm/pnpm/releases/tag/v11.0.5): pnpm 11.0.5 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.4...v11.0.5) ##### Patch Changes - Drop the `darwin-x64` artifact from `@pnpm/exe` and from the GitHub release page. The Node.js SEA mechanism `pnpm pack-app` uses produces a binary that segfaults at startup on Intel Macs because of an upstream Node.js bug ([nodejs/node#62893](https://github.com/nodejs/node/issues/62893), tracked alongside [#&#8203;59553](https://github.com/nodejs/node/issues/59553); the Node.js team has [opted not to fix it](https://github.com/nodejs/node/pull/60250) on the grounds that x64 macOS is being phased out). Re-signing with `codesign` or `ldid` doesn'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 [#&#8203;11423](https://github.com/pnpm/pnpm/issues/11423). - `pnpm dlx` (and `pnpx`/`pnx`/`pnpm create`) now runs the same interactive `approve-builds` prompt as `pnpm add -g` when the package being launched depends on transitive packages with install scripts. Previously, the v11 `strictDepBuilds` default made dlx fail with `ERR_PNPM_IGNORED_BUILDS` and 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 [#&#8203;11444](https://github.com/pnpm/pnpm/issues/11444). - [`72629fc`](https://github.com/pnpm/pnpm/commit/72629fc): Fix `pnpm -g ls --json` and `pnpm -g ls --parseable` so 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 like `npm-check-updates` that parse the JSON output [#&#8203;11440](https://github.com/pnpm/pnpm/issues/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 regular `list` flow is used and the full dependency tree is shown. - Fixed `pnpm publish` to honor `publishConfig.registry` from `package.json` when publishing a single package. The native publish flow introduced in v11 was reading the registry from `.npmrc` only, ignoring the per-package override [#&#8203;11419](https://github.com/pnpm/pnpm/issues/11419). - When `strictPeerDependencies` is `true`, the `ERR_PNPM_PEER_DEP_ISSUES` error once again renders the peer dependency issues inline using the same format as `pnpm peers check`, so users (and CI tools like Renovate) can see what failed without running `pnpm peers check` separately [#&#8203;11439](https://github.com/pnpm/pnpm/issues/11439). - The `WARN` and 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. when `NO_COLOR` is 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 --> ### [`v11.0.4`](https://github.com/pnpm/pnpm/releases/tag/v11.0.4): pnpm 11.0.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.3...v11.0.4) ##### Patch Changes - Fixed `pnpm ci` not reinstalling workspace package `node_modules` directories after the clean step [#&#8203;11427](https://github.com/pnpm/pnpm/issues/11427). - Remove pnpm's workspace state file when cleaning node\_modules so `pnpm ci` performs a fresh install after the clean step. - Do not remove `pnpm-lock.yaml` during `pnpm clean` when `lockfile: true` is configured in `pnpm-workspace.yaml`. The lockfile is only removed when the `--lockfile` option is passed to `pnpm clean`. - `pnpm self-update` (with no version argument) no longer downgrades pnpm when the registry's `latest` dist-tag points to an older release than the currently active version. Run `pnpm self-update latest` to force a downgrade [#&#8203;11418](https://github.com/pnpm/pnpm/issues/11418). - `minimumReleaseAgeStrict` now defaults to `true` whenever the user explicitly sets `minimumReleaseAge` (via `pnpm-workspace.yaml`, the global `config.yaml`, the CLI, or `pnpm_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 --> ### [`v11.0.3`](https://github.com/pnpm/pnpm/releases/tag/v11.0.3): pnpm 11.0.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.2...v11.0.3) ##### Patch Changes - Fix too many open files error sometimes happening on Windows, when creating command shims in `node_modules/.bin` [#&#8203;11412](https://github.com/pnpm/pnpm/issues/11412). - Fix `ERR_PNPM_FETCH_404` when installing a project whose lockfile depends on a `file:` tarball. The previous behavior dropped the `tarball` field from `file:` and git-hosted resolutions when `lockfile-include-tarball-url=false` (the default), even though those URLs cannot be reconstructed from the package name, version, and registry [#&#8203;11407](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.0.2`](https://github.com/pnpm/pnpm/releases/tag/v11.0.2): pnpm 11.0.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.1...v11.0.2) ##### Patch Changes - Fix `ENOENT` symlink failure when `pnpm add -g` triggers the approve-builds prompt. The global add flow used to forward an absolute `modulesDir` (`<installDir>/node_modules`) into the install run by `approve-builds`. The install layer treated `modulesDir` as a path relative to `lockfileDir` and joined it again, producing a doubled path on Windows because `path.join` does not collapse an embedded absolute path. The hoist step then tried to `mkdir` and symlink under `<installDir>\<installDir>\node_modules\.pnpm\node_modules\...` and failed with `ENOENT` [#&#8203;11403](https://github.com/pnpm/pnpm/issues/11403). - Fixed `packageManagerDependencies` going stale when pnpm is invoked through corepack. The lockfile sync (and the `devEngines.packageManager` version 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 [#&#8203;11397](https://github.com/pnpm/pnpm/issues/11397). - Fix recursive publish summaries to report the manifest from `publishConfig.directory` when packages publish from a generated directory [#&#8203;11239](https://github.com/pnpm/pnpm/issues/11239). - Fix negated `os` / `cpu` entries (e.g. `["!win32"]`) being incorrectly rejected when `supportedArchitectures` expands to multiple platforms [#&#8203;11375](https://github.com/pnpm/pnpm/pull/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 --> ### [`v11.0.1`](https://github.com/pnpm/pnpm/releases/tag/v11.0.1): pnpm 11.0.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.0.0...v11.0.1) ##### Patch Changes - Report unknown top-level options before falling back to implicit `pnpm run` scripts. - Reject `null` named catalogs in workspace manifests with `InvalidWorkspaceManifestError` instead of crashing with a raw `TypeError`. - Populate download location for git-sourced dependencies in SBOM output. Previously `pnpm sbom` emitted `NOASSERTION` (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-update` now keeps `package.json`'s `packageManager` and `devEngines.packageManager` in sync. When the legacy `packageManager` field pins pnpm, both fields are rewritten to the new exact pnpm version on update — `packageManager` to `pnpm@<version>` (without an integrity hash), and `devEngines.packageManager.version` to the same exact `<version>` (dropping any range operator). When only `devEngines.packageManager` is declared, the existing range-preserving behavior is unchanged [#&#8203;11388](https://github.com/pnpm/pnpm/issues/11388). - Sort the keys of the overrides object returned by `pnpm audit --fix` so that the log output order matches the order written to `pnpm-workspace.yaml`. - Update the env lockfile's `packageManagerDependencies` entry when `devEngines.packageManager` declares 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 [#&#8203;11387](https://github.com/pnpm/pnpm/issues/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 --> ### [`v11.0.0`](https://github.com/pnpm/pnpm/releases/tag/v11.0.0): pnpm 11 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.34.5...v11.0.0) > Migration guide: [Migrating from v10 to v11](https://pnpm.io/11.x/migration) ##### 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** — `minimumReleaseAge` defaults to 1 day (newly published packages are not resolved for 24h) and `blockExoticSubdeps` defaults to `true`. - **`allowBuilds` replaces the old build-dependency settings** — `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, `neverBuiltDependencies`, `ignoredBuiltDependencies`, and `ignoreDepScripts` have been removed. - **Global installs are isolated and use the global virtual store by default** — each `pnpm add -g` gets its own directory with its own `package.json`, `node_modules`, and lockfile. - **New SQLite-backed store index** (store v11) with bundled manifests and hex digests, reducing filesystem syscalls and speeding up installation. - **Native publish flow** — [`pnpm publish`](https://pnpm.io/11.x/cli/publish), [`login`](https://pnpm.io/11.x/cli/login), [`logout`](https://pnpm.io/11.x/cli/logout), [`view`](https://pnpm.io/11.x/cli/view), [`deprecate`](https://pnpm.io/11.x/cli/deprecate), [`unpublish`](https://pnpm.io/11.x/cli/unpublish), [`dist-tag`](https://pnpm.io/11.x/cli/dist-tag), and [`version`](https://pnpm.io/11.x/cli/version) no longer delegate to the npm CLI, and the remaining npm passthrough commands now throw "not implemented". - **[`pnpm audit`](https://pnpm.io/11.x/cli/audit) uses npm's bulk advisories endpoint** — the legacy `/security/audits` endpoints are gone. CVE-based filtering has been replaced with GHSA-based filtering: migrate `auditConfig.ignoreCves` entries to `auditConfig.ignoreGhsas`. - **`.npmrc` is auth/registry only** — all other settings must live in `pnpm-workspace.yaml` or the new global `config.yaml`, and environment variables use the `pnpm_config_*` prefix. - **Runtime installs are slimmer** — installing a Node.js runtime via `node@runtime:<version>` no longer extracts the bundled `npm`, `npx`, and `corepack`, roughly halving the files pnpm has to hash, write, and link. ##### Minor - **New commands:** [`pnpm ci`](https://pnpm.io/11.x/cli/ci), [`pnpm sbom`](https://pnpm.io/11.x/cli/sbom), [`pnpm clean`](https://pnpm.io/11.x/cli/clean), [`pnpm peers check`](https://pnpm.io/11.x/cli/peers), [`pnpm runtime set`](https://pnpm.io/11.x/cli/runtime), [`pnpm docs`](https://pnpm.io/11.x/cli/docs)/`home`, [`pnpm ping`](https://pnpm.io/11.x/cli/ping), [`pnpm search`](https://pnpm.io/11.x/cli/search), [`pnpm star`](https://pnpm.io/11.x/cli/star)/`unstar`/`stars`, [`pnpm whoami`](https://pnpm.io/11.x/cli/whoami), [`pnpm with`](https://pnpm.io/11.x/cli/with), and [`pnpm pack-app`](https://pnpm.io/11.x/cli/pack-app), plus `pn`/[`pnx`](https://pnpm.io/11.x/cli/pnx) short aliases. - **ESM pnpmfiles** via `.pnpmfile.mjs`, which takes priority over `.pnpmfile.cjs` when present. - **[`pnpm audit --fix=update`](https://pnpm.io/11.x/cli/audit)** fixes vulnerabilities by updating packages in the lockfile instead of adding overrides, and `pnpm audit --fix --interactive` lets you select which advisories to fix. - **[`pnpm pack-app`](https://pnpm.io/11.x/cli/pack-app)** packs 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: `optimisticRepeatInstall` is now `true`, `verifyDepsBeforeRun` is now `install`, `minimumReleaseAge` is now `1440` (1 day), and `minimumReleaseAgeStrict` is `false`. 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, set `minimumReleaseAge: 0` in `pnpm-workspace.yaml` [#&#8203;11158](https://github.com/pnpm/pnpm/pull/11158). - `strictDepBuilds` is `true` by default. - `blockExoticSubdeps` is `true` by default. - Removed deprecated build dependency settings: `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, `neverBuiltDependencies`, `ignoredBuiltDependencies`, and `ignoreDepScripts` [#&#8203;11220](https://github.com/pnpm/pnpm/pull/11220). Use the `allowBuilds` setting instead. It is a map where keys are package name patterns and values are booleans: - `true` means the package is allowed to run build scripts - `false` means 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: ```yaml onlyBuiltDependencies: - electron onlyBuiltDependenciesFile: "allowed-builds.json" neverBuiltDependencies: - core-js ignoredBuiltDependencies: - esbuild ``` After: ```yaml allowBuilds: electron: true core-js: false esbuild: false ``` - Removed `allowNonAppliedPatches` in favor of `allowUnusedPatches`. - Removed `ignorePatchFailures`; patch application failures now throw an error. ##### Store - Runtime dependencies are always linked from the global virtual store [#&#8203;10233](https://github.com/pnpm/pnpm/pull/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.json` from the content-addressable store during resolution and installation. This reduces I/O and speeds up repeat installs [#&#8203;10473](https://github.com/pnpm/pnpm/pull/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.db` with 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 [#&#8203;10500](https://github.com/pnpm/pnpm/pull/10500) [#&#8203;10826](https://github.com/pnpm/pnpm/issues/10826). ##### Global Packages - Global installs (`pnpm add -g pkg`) and `pnx` now use the global virtual store by default. Packages are stored at `{storeDir}/links` instead of per-project `.pnpm` directories. This can be disabled by setting `enableGlobalVirtualStore: false` [#&#8203;10694](https://github.com/pnpm/pnpm/pull/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 package - `pnpm update -g [pkg]` re-installs packages in new isolated directories - `pnpm list -g` scans isolated directories to show all installed global packages - `pnpm install -g` (no args) is no longer supported; use `pnpm add -g <pkg>` instead - Globally installed binaries are now stored in a `bin` subdirectory of `PNPM_HOME` instead of directly in `PNPM_HOME`. This prevents internal directories like `global/` and `store/` from polluting shell autocompletion when `PNPM_HOME` is on PATH [#&#8203;10986](https://github.com/pnpm/pnpm/issues/10986). After upgrading, run `pnpm setup` to 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, use `pnpm link ./foo` instead of `pnpm link foo`. - `pnpm link --global` is removed. Use `pnpm add -g .` to register a local package's bins globally. - `pnpm link` (no arguments) is removed. Use `pnpm link <dir>` with an explicit path instead. ##### Configuration - pnpm no longer reads all settings from `.npmrc`. Only auth and registry settings are read from `.npmrc` files. All other settings (like `hoistPattern`, `nodeLinker`, `shamefullyHoist`, etc.) must be configured in `pnpm-workspace.yaml` or the global `~/.config/pnpm/config.yaml` [#&#8203;11189](https://github.com/pnpm/pnpm/pull/11189). - Network settings (`httpProxy`, `httpsProxy`, `noProxy`, `localAddress`, `strictSsl`, `gitShallowHosts`) are now written to `config.yaml` (global) or `pnpm-workspace.yaml` (local) instead of `.npmrc`/`auth.ini`. They are still readable from `.npmrc` for easier migration from the npm CLI [#&#8203;11209](https://github.com/pnpm/pnpm/pull/11209). pnpm no longer reads `npm_config_*` environment variables. Use `pnpm_config_*` environment variables instead (e.g., `pnpm_config_registry` instead of `npm_config_registry`). pnpm no longer reads the npm global config at `$PREFIX/etc/npmrc`. `pnpm login` writes auth tokens to `~/.config/pnpm/auth.ini`. New `registries` setting in `pnpm-workspace.yaml`: ```yaml registries: default: https://registry.npmjs.org/ "@my-org": https://private.example.com/ "@internal": https://nexus.corp.com/ ``` Auth tokens in `~/.npmrc` still work — pnpm continues to read `~/.npmrc` as a fallback for registry authentication. The new `npmrcAuthFile` setting can be used to point to a different file instead of `~/.npmrc`. - Replace workspace project specific `.npmrc` with `packageConfigs` in `pnpm-workspace.yaml`. A workspace manifest with `packageConfigs` looks something like this: ```yaml # File: pnpm-workspace.yaml packages: - "packages/project-1" - "packages/project-2" packageConfigs: "project-1": saveExact: true "project-2": savePrefix: "~" ``` Or this: ```yaml # 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 `pnpm` field of `package.json`. Settings should be defined in `pnpm-workspace.yaml` [#&#8203;10086](https://github.com/pnpm/pnpm/pull/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 --json` still prints all types of values as JSON, as before. - `pnpm config get <array>` now prints a JSON array. - `pnpm config list` now prints a JSON object instead of INI formatted text. - `pnpm config list` and `pnpm config get` (without argument) now hide auth-related settings. - `pnpm config list` and `pnpm 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 get` and `pnpm config list` no 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 [#&#8203;10642](https://github.com/pnpm/pnpm/pull/10642). Other previously passed-through commands — [`view`](https://pnpm.io/11.x/cli/view) (`info`, `show`, `v`), [`login`](https://pnpm.io/11.x/cli/login) (`adduser`), [`logout`](https://pnpm.io/11.x/cli/logout), [`deprecate`](https://pnpm.io/11.x/cli/deprecate), [`unpublish`](https://pnpm.io/11.x/cli/unpublish), [`dist-tag`](https://pnpm.io/11.x/cli/dist-tag), and [`version`](https://pnpm.io/11.x/cli/version) — have been reimplemented natively in pnpm (see New Commands below). - [`pnpm publish`](https://pnpm.io/11.x/cli/publish) now works without the `npm` CLI. The One-time Password feature now reads from `PNPM_CONFIG_OTP` instead of `NPM_CONFIG_OTP`: ```sh export PNPM_CONFIG_OTP='<your OTP here>' pnpm publish --no-git-checks ``` If the registry requests OTP and the user has not provided it via the `PNPM_CONFIG_OTP` environment variable or the `--otp` flag, 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 publish` no longer calls `npm 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 use `pnpm pack && npm publish *.tgz` as a workaround. - Removed the `pnpm server` command [#&#8203;10463](https://github.com/pnpm/pnpm/pull/10463). - Removed support for the `useNodeVersion` and `executionEnv.nodeVersion` fields. `devEngines.runtime` and `engines.runtime` should be used instead [#&#8203;10373](https://github.com/pnpm/pnpm/pull/10373). - Removed support for `hooks.fetchers`. We now have a new API for custom fetchers and resolvers via the `fetchers` field of `pnpmfile`. ##### Lifecycle Scripts - pnpm no longer populates `npm_config_*` environment variables from the pnpm config during lifecycle scripts. Only well-known `npm_*` env vars are now set, matching Yarn's behavior [#&#8203;11116](https://github.com/pnpm/pnpm/pull/11116). ##### CLI Output - Cleaner output for script execution: pnpm now prints `$ command` instead of `> pkg@version stage path\n> command`, and shows project name and path only when running in a different directory. The `$ command` line is printed to stderr to keep stdout clean for piping [#&#8203;11132](https://github.com/pnpm/pnpm/pull/11132). - During install, instead of rendering the full peer dependency issues tree, pnpm now suggests running [`pnpm peers check`](https://pnpm.io/11.x/cli/peers) to view the issues [#&#8203;11133](https://github.com/pnpm/pnpm/pull/11133). ##### Lockfile - Simplified `patchedDependencies` lockfile format from `Record<string, { path: string, hash: string }>` to `Record<string, string>` (selector to hash). Existing lockfiles with the old format are automatically migrated [#&#8203;10911](https://github.com/pnpm/pnpm/pull/10911). ##### Other - The default value of the `type` field in the `package.json` file of the project initialized by `pnpm init` command has been changed to `module`. - Added support for lowercase options in `pnpm add`: `-d`, `-p`, `-o`, `-e` [#&#8203;9197](https://github.com/pnpm/pnpm/issues/9197). When using the `pnpm add` command only: - `-p` is now an alias for `--save-prod` instead of `--parseable` - `-d` is now an alias for `--save-dev` instead of `--loglevel=info` - The root workspace project is no longer excluded when it is explicitly selected via a filter [#&#8203;10465](https://github.com/pnpm/pnpm/pull/10465). ##### Audit - [`pnpm audit`](https://pnpm.io/11.x/cli/audit) now calls npm's `/-/npm/v1/security/advisories/bulk` endpoint. 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-unfixable` now 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-NNNNN` entry in your `auditConfig.ignoreCves` with the corresponding `GHSA-xxxx-xxxx-xxxx` value (visible in the `More info` column of `pnpm audit` output) and move it under `auditConfig.ignoreGhsas`. ##### Package Manager Settings - **Breaking:** removed the `managePackageManagerVersions`, `packageManagerStrict`, and `packageManagerStrictVersion` settings. They existed only to derive the `onFail` behavior for the legacy `packageManager` field, and the `pmOnFail` setting introduced alongside [`pnpm with`](https://pnpm.io/11.x/cli/with) subsumes all three — it directly sets the `onFail` behavior of both `packageManager` and `devEngines.packageManager`. The `COREPACK_ENABLE_STRICT` environment variable is no longer honored (it only gated `packageManagerStrict`); use `pmOnFail` instead. Migration: | Removed setting | Replace with | | ------------------------------------- | ------------------------------ | | `managePackageManagerVersions: true` | `pmOnFail: download` (default) | | `managePackageManagerVersions: false` | `pmOnFail: ignore` | | `packageManagerStrict: false` | `pmOnFail: warn` | | `packageManagerStrictVersion: true` | `pmOnFail: error` | | `COREPACK_ENABLE_STRICT=0` | `pmOnFail: warn` | ##### Runtime Installs - Installing a Node.js runtime via `node@runtime:<version>` (including `pnpm env use` and `pnpm runtime set node`) no longer extracts the bundled `npm`, `npx`, and `corepack` from the Node.js archive. 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 need `npm` can install it as a separate package. ##### Minor Changes ##### New Commands - Added native [`pnpm view`](https://pnpm.io/11.x/cli/view) (`info`, `show`, `v`) command for viewing package metadata from the registry [#&#8203;11064](https://github.com/pnpm/pnpm/pull/11064). - Added [`pnpm login`](https://pnpm.io/11.x/cli/login) (and `pnpm adduser` alias) command for authenticating with npm registries. Supports web-based login with QR code as well as classic username/password login [#&#8203;11094](https://github.com/pnpm/pnpm/pull/11094). - Added [`pnpm logout`](https://pnpm.io/11.x/cli/logout) command for logging out of npm registries. Revokes the authentication token on the registry and removes it from the local auth config file [#&#8203;11213](https://github.com/pnpm/pnpm/pull/11213). - Added native [`pnpm deprecate`](https://pnpm.io/11.x/cli/deprecate) and `pnpm undeprecate` commands for setting and removing deprecation messages on package versions without delegating to the npm CLI [#&#8203;11120](https://github.com/pnpm/pnpm/pull/11120). - Added native [`pnpm unpublish`](https://pnpm.io/11.x/cli/unpublish) command. Supports unpublishing specific versions, version ranges via semver, and entire packages with `--force` [#&#8203;11128](https://github.com/pnpm/pnpm/pull/11128). - Added native [`pnpm dist-tag`](https://pnpm.io/11.x/cli/dist-tag) command (`ls`, `add`, `rm` subcommands) [#&#8203;11218](https://github.com/pnpm/pnpm/pull/11218). - Added [`pnpm sbom`](https://pnpm.io/11.x/cli/sbom) command for generating Software Bill of Materials in CycloneDX 1.7 and SPDX 2.3 JSON formats [#&#8203;9088](https://github.com/pnpm/pnpm/issues/9088). - Added [`pnpm clean`](https://pnpm.io/11.x/cli/clean) command that safely removes `node_modules` directories from all workspace projects [#&#8203;10707](https://github.com/pnpm/pnpm/issues/10707). Use `--lockfile` to also remove `pnpm-lock.yaml` files. - Added a new command [`pnpm runtime set <runtime name> <runtime version spec> [-g]`](https://pnpm.io/11.x/cli/runtime) for installing runtimes. Deprecated `pnpm env use` in 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`](https://pnpm.io/11.x/cli/audit) [#&#8203;10341](https://github.com/pnpm/pnpm/pull/10341). - Added [`pnpm ci`](https://pnpm.io/11.x/cli/ci) command for clean installs [#&#8203;6100](https://github.com/pnpm/pnpm/issues/6100). The command runs `pnpm clean` followed by `pnpm install --frozen-lockfile`. Designed for CI/CD environments where reproducible builds are critical. Aliases: `pnpm clean-install`, `pnpm ic`, `pnpm install-clean` [#&#8203;11003](https://github.com/pnpm/pnpm/pull/11003). - Added [`pnpm peers check`](https://pnpm.io/11.x/cli/peers) command that checks for unmet and missing peer dependency issues by reading the lockfile [#&#8203;7087](https://github.com/pnpm/pnpm/issues/7087). - Implemented the [`version`](https://pnpm.io/11.x/cli/version) command natively in pnpm to support workspaces and `workspace:` protocols correctly. The new command allows bumping package versions (major, minor, patch, etc.) with full workspace support and git integration [#&#8203;10879](https://github.com/pnpm/pnpm/pull/10879). - [`pnpm audit --fix`](https://pnpm.io/11.x/cli/audit) now supports a new interactive mode via `--interactive`/`-i`. - Added the [`pnpm docs`](https://pnpm.io/11.x/cli/docs) command and its alias `pnpm home`. This command opens the package documentation or homepage in the browser. When the package has no valid homepage, it falls back to `https://npmx.dev/package/<name>`. - Added native [`pnpm ping`](https://pnpm.io/11.x/cli/ping) command to test registry connectivity. Provides a simple way to verify connectivity to the configured registry without requiring external tools. - Implemented native [`search`](https://pnpm.io/11.x/cli/search) command and its aliases (`s`, `se`, `find`). - Implemented native [`star`, `unstar`, `stars`](https://pnpm.io/11.x/cli/star), and [`whoami`](https://pnpm.io/11.x/cli/whoami) commands. - Add [`pnpm with <version|current> <args...>`](https://pnpm.io/11.x/cli/with) command. Runs pnpm at a specific version (or the currently active one) for a single invocation, bypassing the project's `packageManager` and `devEngines.packageManager` pins. - Added a new [`pnpm pack-app`](https://pnpm.io/11.x/cli/pack-app) command that packs a CommonJS entry file into a standalone executable for one or more target platforms, using the [Node.js Single Executable Applications](https://nodejs.org/api/single-executable-applications.html) 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 `rc` file and local `.npmrc`. - pnpm-specific settings, which can only be loaded from YAML files such as the global `config.yaml` and local `pnpm-workspace.yaml`. - Added support for loading environment variables whose names start with `pnpm_config_` into config. These environment variables override settings from `pnpm-workspace.yaml` but not CLI arguments. - Added support for reading `allowBuilds` from `pnpm-workspace.yaml` in the global package directory for global installs. - Added support for `pnpm config get globalconfig` to retrieve the global config file path [#&#8203;9977](https://github.com/pnpm/pnpm/issues/9977). - Added a new setting `virtualStoreOnly` that 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 fetch` now uses this mode internally [#&#8203;10840](https://github.com/pnpm/pnpm/issues/10840). - Added support for specifying the pnpm version via `devEngines.packageManager` in `package.json`. Unlike the `packageManager` field, this supports version ranges. The resolved version is stored in `pnpm-lock.yaml` and reused if it still satisfies the range [#&#8203;10932](https://github.com/pnpm/pnpm/pull/10932). - Added a new `dedupePeers` setting 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 `(foo@1.0.0(bar@2.0.0))`. This dramatically reduces the number of package instances in projects with many recursive peer dependencies [#&#8203;11070](https://github.com/pnpm/pnpm/issues/11070). - Config dependencies are now installed into the global virtual store (`{storeDir}/links/`) and symlinked into `node_modules/.pnpm-config/`. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports [#&#8203;10910](https://github.com/pnpm/pnpm/pull/10910). Config dependency and package manager integrity info is now stored in `pnpm-lock.yaml` instead of inlined in `pnpm-workspace.yaml`: the workspace manifest contains only clean version specifiers for `configDependencies`, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also stores `packageManagerDependencies` resolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install [#&#8203;10912](https://github.com/pnpm/pnpm/pull/10912) [#&#8203;10964](https://github.com/pnpm/pnpm/pull/10964). - Added `nodeDownloadMirrors` setting to configure custom Node.js download mirrors in `pnpm-workspace.yaml`. This replaces the `node-mirror:<channel>` `.npmrc` setting, which is no longer read [#&#8203;11194](https://github.com/pnpm/pnpm/pull/11194): ```yaml nodeDownloadMirrors: release: https://my-mirror.example.com/download/release/ ``` - `pnpm dlx` and `pnpm create` now respect security and trust policy settings (`minimumReleaseAge`, `minimumReleaseAgeExclude`, `minimumReleaseAgeStrict`, `trustPolicy`, `trustPolicyExclude`, `trustPolicyIgnoreAfter`) from project-level configuration [#&#8203;11183](https://github.com/pnpm/pnpm/issues/11183). - `pnpm init` now writes a `devEngines.packageManager` field instead of the `packageManager` field when `init-package-manager` is enabled. - Added a new setting `runtimeOnFail` that overrides the `onFail` field of `devEngines.runtime` (and `engines.runtime`) in the root project's `package.json`. Accepted values: `ignore`, `warn`, `error`, `download`. For example, setting `runtimeOnFail=download` makes pnpm download the declared runtime version even when the manifest does not set `onFail: "download"`. - Added a new setting `minimumReleaseAgeIgnoreMissingTime`, which is `true` by default. When enabled, pnpm skips the `minimumReleaseAge` maturity check if the registry metadata does not include the `time` field. Set to `false` to 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 [#&#8203;10837](https://github.com/pnpm/pnpm/issues/10837). ##### Hooks & Pnpmfiles - Added support for pnpmfiles written in ESM, using the `.mjs` extension. When `.pnpmfile.mjs` exists, it takes priority over `.pnpmfile.cjs` and only one is loaded [#&#8203;9730](https://github.com/pnpm/pnpm/pull/9730). ##### CLI & Other - The built-in `clean`, `setup`, `deploy`, and `rebuild` commands now prefer user scripts over built-in commands. When a project's `package.json` has a script with the same name, `pnpm` executes the script instead of the built-in command. Added `purge` as an alias for the built-in `clean` command, which always runs the built-in regardless of scripts [#&#8203;11118](https://github.com/pnpm/pnpm/pull/11118). - Added `-F` as a short alias for the `--filter` option. - Added support for hidden scripts. Scripts starting with `.` are hidden and cannot be run directly via `pnpm run`. They can only be called from other scripts. Hidden scripts are also omitted from the `pnpm run` listing [#&#8203;11041](https://github.com/pnpm/pnpm/pull/11041). - `pnpm approve-builds` now 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 [#&#8203;11030](https://github.com/pnpm/pnpm/pull/11030). - During install, packages with ignored builds that are not yet listed in `allowBuilds` are automatically added to `pnpm-workspace.yaml` with a placeholder value, so users can manually set them to `true` or `false` [#&#8203;11030](https://github.com/pnpm/pnpm/pull/11030). - Added `pn` and `pnx` short aliases for `pnpm` and `pnpx` (`pnpm dlx`) [#&#8203;11052](https://github.com/pnpm/pnpm/pull/11052). - `pnpm store prune` now displays the total size of removed files [#&#8203;11047](https://github.com/pnpm/pnpm/pull/11047). - `pnpm audit --fix` now adds the minimum patched version for each advisory to `minimumReleaseAgeExclude` in `pnpm-workspace.yaml`, so the security fix can be installed without waiting for `minimumReleaseAge` [#&#8203;11216](https://github.com/pnpm/pnpm/pull/11216). - pnpm now warns when `optimisticRepeatInstall` skips `shouldRefreshResolution` hooks [#&#8203;10995](https://github.com/pnpm/pnpm/pull/10995). ##### Performance - Replaced `node-fetch` with native `undici` for HTTP requests throughout pnpm [#&#8203;10537](https://github.com/pnpm/pnpm/pull/10537). - Eliminated redundant internal linking during GVS warm reinstall when no packages were added [#&#8203;11073](https://github.com/pnpm/pnpm/pull/11073). - Eliminated the staging directory when importing packages into `node_modules`, avoiding the overhead of creating a temp dir and renaming per package [#&#8203;11088](https://github.com/pnpm/pnpm/pull/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 [#&#8203;11087](https://github.com/pnpm/pnpm/pull/11087). - Optimized hot-path string operations in the content-addressable store and increased `gunzipSync` chunk size for fewer buffer allocations during tarball decompression [#&#8203;11086](https://github.com/pnpm/pnpm/pull/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 [#&#8203;11151](https://github.com/pnpm/pnpm/pull/11151). - Adopted `If-Modified-Since` for conditional metadata fetches, avoiding re-downloading unchanged registry metadata [#&#8203;11161](https://github.com/pnpm/pnpm/pull/11161). - Switched to abbreviated metadata when checking `minimumReleaseAge`, reducing the amount of data fetched from the registry [#&#8203;11160](https://github.com/pnpm/pnpm/pull/11160). - Switched the metadata cache to NDJSON format, improving read/write performance [#&#8203;11188](https://github.com/pnpm/pnpm/pull/11188). ##### Patch Changes - Switched to `process.stderr.write` instead of `console.error` for script logging [#&#8203;11140](https://github.com/pnpm/pnpm/pull/11140). - Respected the `frozen-lockfile` flag when migrating config dependencies [#&#8203;11067](https://github.com/pnpm/pnpm/pull/11067). - Removed the `--workspace` flag from the `version` command [#&#8203;11115](https://github.com/pnpm/pnpm/pull/11115). - Handled `ENOTSUP` error in the clone import path during parallel I/O [#&#8203;11117](https://github.com/pnpm/pnpm/pull/11117). - Fixed `pnpm audit` command. - 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 `rc` config file to `npm`. - Fixed YAML formatting preservation in `pnpm-workspace.yaml` when running commands like `pnpm update`. Previously, quotes and other formatting were lost even when catalog values didn't change. Closes [#&#8203;10425](https://github.com/pnpm/pnpm/issues/10425) - The parameter set by the `--allow-build` flag is now written to `allowBuilds`. - Fixed a bug in which specifying `filter` in `pnpm-workspace.yaml` would 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 [#&#8203;10978](https://github.com/pnpm/pnpm/pull/10978). - Fixed `strictDepBuilds` and `allowBuilds` checks being bypassed when a package's build side-effects are cached in the store [#&#8203;11039](https://github.com/pnpm/pnpm/pull/11039). - In GVS mode, `pnpm approve-builds` now runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changing `allowBuilds` [#&#8203;11043](https://github.com/pnpm/pnpm/pull/11043). - Fixed a crash in the lockfile merger when merging non-semver version strings (e.g. `link:`, `file:`, git URLs) [#&#8203;11102](https://github.com/pnpm/pnpm/pull/11102). - Handled `ENOTSUP` error in `linkOrCopy` during parallel imports [#&#8203;11103](https://github.com/pnpm/pnpm/pull/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) [#&#8203;11069](https://github.com/pnpm/pnpm/pull/11069). - Fixed `_password` handling for the default registry to decode from base64 before use, consistent with scoped registry behavior [#&#8203;11089](https://github.com/pnpm/pnpm/pull/11089). - Fixed a bug where the CAS locker cache was not updated when a file already existed with correct integrity [#&#8203;11085](https://github.com/pnpm/pnpm/pull/11085). - Prevented catalog entries from being removed by `cleanupUnusedCatalogs` when they are referenced only from workspace `overrides` [#&#8203;11075](https://github.com/pnpm/pnpm/pull/11075). - Resolved patch file paths during `pnpm fetch` [#&#8203;11054](https://github.com/pnpm/pnpm/pull/11054). - Fixed invalid specifiers for peers on all non-exact version selectors [#&#8203;11049](https://github.com/pnpm/pnpm/pull/11049). - Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code [#&#8203;11000](https://github.com/pnpm/pnpm/issues/11000). - Prepended `Bearer` to the authorization token generated by `tokenHelper` if it is missing, aligning with npm's behavior [#&#8203;11097](https://github.com/pnpm/pnpm/pull/11097). - Propagated error cause when throwing `PnpmError` in `@pnpm/npm-resolver` [#&#8203;10990](https://github.com/pnpm/pnpm/pull/10990). - Fixed SQLite race condition during store initialization on Windows. - Removed `rimrafSync` in `importIndexedDir` fast-path error handler [#&#8203;11168](https://github.com/pnpm/pnpm/pull/11168). - Fixed `pnpm dedupe --check` unexpectedly failing due to non-deterministic resolution [#&#8203;11110](https://github.com/pnpm/pnpm/pull/11110). - Fixed empty files not being rejected in `isEmptyDirOrNothing` [#&#8203;11182](https://github.com/pnpm/pnpm/pull/11182). - Fixed `.bat`/`.cmd` token helpers not working on Windows due to missing `shell: true` option. <!-- 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 --> ### [`v10.34.5`](https://github.com/pnpm/pnpm/releases/tag/v10.34.5): pnpm 10.34.5 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.34.4...v10.34.5) ##### Patch Changes - [`78e29fe`](https://github.com/pnpm/pnpm/commit/78e29fe): Prevent a crafted `pnpm-lock.yaml` from writing package content outside the virtual store. A dependency path key whose name reconstructs to a path-traversal sequence (e.g. `../../../tmp/x@1.0.0`) is now rejected by the isolated (virtual-store) linker and the Plug'n'Play resolver map, matching the containment already applied to the hoisted linker. Under the global virtual store, a traversal in the version-derived path segment (e.g. a snapshot `version: "../../x"`) is now rejected at `iterateHashedGraphNodes`, the single point every global-virtual-store slot path funnels through. - [`78e29fe`](https://github.com/pnpm/pnpm/commit/78e29fe): Fixed a path traversal vulnerability where a dependency whose manifest `name` was a scoped path traversal (e.g. `@x/../../../<path>`) could be written outside `node_modules` to an attacker-controlled location during `pnpm install`, even with `--ignore-scripts`. The isolated linker now validates the package name before using it as a directory name, matching the existing protection in the hoisted linker. - [`47ef6f0`](https://github.com/pnpm/pnpm/commit/47ef6f0): Fixed switching to and self-updating to pnpm v12. pnpm v12 (the Rust port) ships as the `pnpm` and `@pnpm/exe` npm packages whose bins are placeholders replaced at install time by the host's native binary from a `@pnpm/exe.<platform>-<arch>[-musl]` optional dependency. Because pnpm installs its own engine with `--ignore-scripts`, that relinking never ran, leaving a non-executable placeholder. pnpm now relinks the native binary itself for v12 (recognizing the new platform-package naming scheme and the native `pnpm` package), and verifies the native binary's npm registry signature before running it. - [`36928be`](https://github.com/pnpm/pnpm/commit/36928be): `${...}` environment-variable placeholders in the `httpProxy`, `httpsProxy`, `noProxy`, `proxy`, and `noproxy` settings are no longer expanded when these settings come from a project's `pnpm-workspace.yaml`. They now receive the same protection already applied to `registry`. <!-- 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 --> ### [`v10.34.4`](https://github.com/pnpm/pnpm/releases/tag/v10.34.4): pnpm 10.34.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.34.3...v10.34.4) ##### Patch Changes - [`352ae48`](https://github.com/pnpm/pnpm/commit/352ae48): Security: validate config dependency names and versions before using them to build filesystem paths. A `pnpm-workspace.yaml` with a traversal-shaped `configDependencies` name (such as `../../PWNED`) or version (such as `../../../PWNED`) could previously cause `pnpm install` to create symlinks or write package files outside `node_modules/.pnpm-config` and the store. Names must now be valid npm package names and versions must be exact semver versions. See [GHSA-qrv3-253h-g69c](https://github.com/pnpm/pnpm/security/advisories/GHSA-qrv3-253h-g69c). - [`352ae48`](https://github.com/pnpm/pnpm/commit/352ae48): Reject path-traversal and reserved dependency aliases (such as `../../../escape`, `.bin`, `.pnpm`, or `node_modules`) that come from a lockfile rather than a freshly resolved manifest. A crafted lockfile alias could otherwise be joined directly under a hoisted `node_modules` directory, letting package files be written outside the intended install root or overwrite pnpm-owned layout. The `nodeLinker: hoisted` graph builder now validates each alias at the directory sink (`safeJoinModulesDir`), matching the validation pnpm already performs when resolving aliases from manifests. See [GHSA-fr4h-3cph-29xv](https://github.com/pnpm/pnpm/security/advisories/GHSA-fr4h-3cph-29xv). - [`352ae48`](https://github.com/pnpm/pnpm/commit/352ae48): Prevent `pnpm patch-remove` from removing files outside the configured patches directory. - [`217fbe0`](https://github.com/pnpm/pnpm/commit/217fbe0): Hardened the warning printed when a project `.npmrc` uses environment variables in registry/auth settings: the suggested `pnpm config set` command is now only included for keys made up of shell-inert characters. Because the key comes from a repository-controlled `.npmrc` and a shell expands `$(...)`, backticks, and `$VAR` even inside double quotes, a crafted key could otherwise have turned the suggested copy-paste command into command execution. <!-- 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 --> ### [`v10.34.3`](https://github.com/pnpm/pnpm/releases/tag/v10.34.3): pnpm 10.34.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.34.2...v10.34.3) ##### ⚠️ Security fix — environment variables in a project `.npmrc` (action may be required) Following [GHSA-3qhv-2rgh-x77r](https://github.com/pnpm/pnpm/security/advisories/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`. This release also closes a bypass where a project `.npmrc` could set `userconfig`, `globalconfig`, or `prefix` to make pnpm load a repo-supplied file as *trusted* config (via `@pnpm/npm-conf@3.0.3`). 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`: ```sh # 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 `~/.npmrc` instead of the repo. In **GitHub Actions**, `actions/setup-node` with `registry-url` already writes a user-level `.npmrc`, so `NODE_AUTH_TOKEN` keeps working. For other CI where editing each pipeline is hard, set `NPM_CONFIG_USERCONFIG=.npmrc` in the CI environment to declare the project `.npmrc` trusted. See <https://pnpm.io/npmrc> for full migration details. ##### Patch Changes - Improved the warning printed when a project `.npmrc` uses 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 running `pnpm config set "<key>" <value>` to store it in the global config, or by keeping the `${...}` line in the user-level `~/.npmrc` — with a link to <https://pnpm.io/npmrc>. - A repository-controlled project or workspace `.npmrc` can no longer redirect which files pnpm loads as its trusted user and global configuration. Previously such a file could set `userconfig`, `globalconfig`, or `prefix` to point at an attacker-supplied file shipped in the repository, and pnpm would load it as a trusted config source — bypassing the protection that prevents repository config from expanding environment variables into registry request destinations and credentials, and allowing it to set `tokenHelper`. The user/global config file locations are now resolved only from trusted sources (CLI options, environment config, the npm builtin config, and defaults) before the project and workspace `.npmrc` files are read. Fixed by upgrading `@pnpm/npm-conf` to `3.0.3`. <!-- 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 --> ### [`v10.34.2`](https://github.com/pnpm/pnpm/releases/tag/v10.34.2): pnpm 10.34.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.34.1...v10.34.2) ##### ⚠️ Security fix — environment variables in a project `.npmrc` (action may be required) Following [GHSA-3qhv-2rgh-x77r](https://github.com/pnpm/pnpm/security/advisories/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`. This release also closes a bypass where a project `.npmrc` could set `userconfig`, `globalconfig`, or `prefix` to make pnpm load a repo-supplied file as *trusted* config (via `@pnpm/npm-conf@3.0.3`). 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`: ```sh # 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 `~/.npmrc` instead of the repo. In **GitHub Actions**, `actions/setup-node` with `registry-url` already writes a user-level `.npmrc`, so `NODE_AUTH_TOKEN` keeps working. For other CI where editing each pipeline is hard, set `NPM_CONFIG_USERCONFIG=.npmrc` in the CI environment to declare the project `.npmrc` trusted. See <https://pnpm.io/npmrc> for full migration details. ##### Patch Changes - Package-manager bootstrap traffic is now resolved through trusted registries and trusted network config. When pnpm downloads the pnpm version requested by a repository's `packageManager` field, the registry it fetches from (and the proxy/TLS settings used for that traffic) now come exclusively from trusted config sources — CLI options, env config, user and global `.npmrc` — defaulting to the public npm registry, instead of the repository's project/workspace settings. - pnpm now verifies the npm registry signature of a package-manager binary before spawning it. When the `packageManager` field (or `pnpm self-update`) makes pnpm download another pnpm version, the staged install is verified corepack-style: the integrity recorded in the staged lockfile must carry a valid npm registry signature for the exact `name@version`, validated against npm's public signing keys that ship embedded in the pnpm CLI. Verification fails closed — a tampered download, an unsigned package, or an unreachable registry refuses the version switch rather than running an unverified binary. It runs only when the wanted version is actually downloaded (a tools-directory cache miss), so repeated commands pay no extra network round trip. - Environment variable expansion is now trust-aware for registry/auth config and request destinations. Repository-controlled config files (the project and workspace `.npmrc` and `pnpm-workspace.yaml`) can no longer expand `${...}` placeholders in registry/proxy request destinations, URL-scoped keys, or registry credential values, preventing repository-controlled configuration from exfiltrating environment secrets through request URLs. Trusted user/global/CLI/env config keeps full env expansion, so existing token and registry setup flows continue to work. - Reject reserved manifest `bin` names (`""`, `"."`, `".."`, 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 `onlyBuiltDependencies` (and `allowBuilds`) entries 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 the key. Lockfile entries are now rejected when 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. - pnpm now verifies the detached OpenPGP signature of a Node.js release's `SHASUMS256.txt` against the Node.js release team's public keys (embedded in the pnpm CLI) before trusting its hashes. The Node.js download mirror is repository-configurable (`node-mirror:<channel>` in `.npmrc`), and the integrity check previously trusted a `SHASUMS256.txt` fetched from that same mirror — a circular check that a malicious mirror could satisfy with a tampered binary and matching hashes. A mirror that proxies the real signed SHASUMS keeps working unchanged. Only the `release` channel publishes signed SHASUMS files, so pre-release channels (rc, nightly, …) remain unverified. <!-- 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 --> ### [`v10.34.1`](https://github.com/pnpm/pnpm/releases/tag/v10.34.1): pnpm 10.34.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.34.0...v10.34.1) ##### Patch Changes - Reject `pnpm-lock.yaml` entries whose remote tarball `resolution:` block is missing the `integrity` field. 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 strips `integrity:`) 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 with `ERR_PNPM_MISSING_TARBALL_INTEGRITY`. Git-hosted tarballs (`gitHosted: true` or a URL on codeload.github.com / bitbucket.org / gitlab.com) and `file:` tarballs are exempt — the commit SHA in a git-host URL and the user-controlled local path already anchor the bytes. <!-- 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 --> ### [`v10.34.0`](https://github.com/pnpm/pnpm/releases/tag/v10.34.0): pnpm 10.34 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.33.4...v10.34.0) ##### Minor Changes - Treat tarball-integrity mismatches against the lockfile as a hard failure by default. Previously, `pnpm install` (non-frozen) would log `ERR_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 install` now exits with `ERR_PNPM_TARBALL_INTEGRITY` and 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. `--force` and `pnpm update` deliberately 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-lockfile` behavior is unchanged. `--fix-lockfile` keeps its documented purpose (filling in missing lockfile entries) and is also not a bypass. ##### Patch Changes - Pin unscoped per-registry settings (`_authToken`, `_auth`, `username`/`_password`, `tokenHelper`, inline `cert`/`key`) to the registry declared in the same config source at load time, so a later layer overriding `registry=` (workspace `.npmrc`, `pnpm-workspace.yaml`, CLI `--registry`) cannot redirect a credential or client certificate authored for a different host. A deprecation warning is emitted whenever an unscoped per-registry setting is encountered, naming the source and the URL it was pinned to. Reported by JUNYI LIU. - Fixed `minimumReleaseAge` handling when cached metadata is abbreviated. The npm registry returns abbreviated package metadata (without the per-version `time` field) by default, which made the maturity check throw `ERR_PNPM_MISSING_TIME` whenever cached abbreviated metadata was reused. pnpm now upgrades cached abbreviated metadata to the full document via a follow-up fetch when `minimumReleaseAge` is active, persists the upgrade to the on-disk cache so subsequent installs skip the extra fetch, and lets `ERR_PNPM_MISSING_TIME` from the cache fast-path fall through to the network fetch even under strict mode. - Reject git resolutions whose `commit` field is not a 40-character hexadecimal SHA before invoking `git`. A malicious lockfile could otherwise smuggle a value such as `--upload-pack=<command>` through `git fetch` / `git checkout`, which on SSH or local-file transports executes the supplied command. - Reject patch files whose `diff --git` headers reference paths outside the patched package directory. Previously a malicious `.patch` file added via a pull request could write, delete, or rename arbitrary files reachable by the user running `pnpm install`. - Fixed `--prefix=<dir>` not being honored when locating the workspace root. The `--prefix → dir` rename was applied after workspace detection, so workspace settings declared in `<dir>/pnpm-workspace.yaml` were not loaded when pnpm was invoked from outside `<dir>` [#&#8203;11535](https://github.com/pnpm/pnpm/issues/11535). - Reject dependency aliases that contain path-traversal segments (such as `@x/../../../../../.git/hooks`) when reading them from a package manifest or symlinking them into `node_modules`. A malicious registry package could otherwise use a transitive dependency key to make `pnpm install` create symlinks at attacker-chosen paths outside the intended `node_modules` directory. <!-- 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 --> ### [`v10.33.4`](https://github.com/pnpm/pnpm/releases/tag/v10.33.4): pnpm 10.33.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.33.3...v10.33.4) ##### Patch Changes - 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: true` field 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. - Fix a regression where `pnpm --recursive --filter '!<pkg>' run/exec/test/add` would include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative `--filter` arguments are provided, matching the [documented behavior](https://pnpm.io/cli/recursive). To include the root, pass `--include-workspace-root` [#&#8203;11341](https://github.com/pnpm/pnpm/issues/11341). <!-- 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 --> ### [`v10.33.3`](https://github.com/pnpm/pnpm/releases/tag/v10.33.3): pnpm 10.33.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.33.2...v10.33.3) ##### Patch Changes - When self-updating from v10's `@pnpm/exe` to v11+ on Intel macOS (darwin-x64), `pnpm self-update` now transparently switches to the JS-only `pnpm` package on npm instead of installing `@pnpm/exe@v11+` (which doesn't ship a working binary for Intel Macs because of an upstream Node.js SEA bug — see [#&#8203;11423](https://github.com/pnpm/pnpm/issues/11423) and [nodejs/node#62893](https://github.com/nodejs/node/issues/62893)). Without this, the self-update would silently leave the user with no working `pnpm` binary. The new install requires Node.js to be available on `PATH`; a warning is printed when the swap happens. All other host/version combinations are unchanged. - `pnpm self-update` (with no version argument) no longer downgrades pnpm when the registry's `latest` dist-tag points to an older release than the currently active version. Run `pnpm self-update latest` to force a downgrade [#&#8203;11418](https://github.com/pnpm/pnpm/issues/11418). <!-- 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 --> ### [`v10.33.2`](https://github.com/pnpm/pnpm/releases/tag/v10.33.2): pnpm 10.33.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.33.1...v10.33.2) ##### Patch Changes - Globally-installed bins no longer fail with `ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND` when pnpm was installed via the standalone `@pnpm/exe` binary (e.g. `curl -fsSL https://get.pnpm.io/install.sh | sh -`) on a system without a separate Node.js installation. Previously, when `which('node')` failed during `pnpm add --global`, pnpm fell back to `process.execPath`, which in `@pnpm/exe` is the pnpm binary itself — and that path was baked into the generated bin shim, causing the shim to invoke pnpm instead of Node [#&#8203;11291](https://github.com/pnpm/pnpm/issues/11291), [#&#8203;4645](https://github.com/pnpm/pnpm/issues/4645). - Fix an infinite fork-bomb that could happen when pnpm was installed with one version (e.g. `npm install -g pnpm@A`) and run inside a project whose `package.json` selected a different pnpm version via the `packageManager` field (e.g. `pnpm@B`), while a `pnpm-workspace.yaml` also existed at the project root. The child's environment is now forced to `manage-package-manager-versions=false` (v10) and `pm-on-fail=ignore` (v11+), which disables the package-manager-version handling in whichever pnpm runs as the child. Fixes [#&#8203;11337](https://github.com/pnpm/pnpm/issues/11337). <!-- 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 --> ### [`v10.33.1`](https://github.com/pnpm/pnpm/releases/tag/v10.33.1): pnpm 10.33.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.33.0...v10.33.1) ##### Patch Changes - When a project's `packageManager` field selects pnpm v11 or newer, commands that v10 would have passed through to npm (`version`, `login`, `logout`, `publish`, `unpublish`, `deprecate`, `dist-tag`, `docs`, `ping`, `search`, `star`, `stars`, `unstar`, `whoami`, etc.) are now handed over to the wanted pnpm, which implements them natively. Previously they silently shelled out to npm — making, for example, `pnpm version --help` print npm's help on a project with `packageManager: pnpm@11.0.0-rc.3` [#&#8203;11328](https://github.com/pnpm/pnpm/issues/11328). <!-- 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 --> ### [`v10.33.0`](https://github.com/pnpm/pnpm/releases/tag/v10.33.0): pnpm 10.33 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.32.1...v10.33.0) ##### Minor Changes - Added a new `dedupePeers` setting 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 `(foo@1.0.0(bar@2.0.0))`. This dramatically reduces the number of package instances in projects with many recursive peer dependencies [#&#8203;11070](https://github.com/pnpm/pnpm/issues/11070). ##### Patch Changes - Fail on incompatible lockfiles in CI when frozen lockfile mode is enabled, while preserving non-frozen CI fallback behavior. - When package metadata is malformed or can't be fetched, the error thrown will now show the originating error. - Fixed intermittent failures when multiple `pnpm dlx` calls run concurrently for the same package. When the global virtual store is enabled, the importer now verifies file content before skipping a rename, avoiding destructive swap-renames that break concurrent processes. Also tolerates EPERM during bin creation on Windows and properly propagates `enableGlobalVirtualStore` through the install pipeline. - Fixed handling of non-string version selectors in `hoistPeers`, preventing invalid peer dependency specifiers. - Improve the non-interactive modules purge error hint to include the `confirmModulesPurge=false` workaround. When pnpm needs to recreate `node_modules` but no TTY is available, the error now suggests either setting `CI=true` or disabling the purge confirmation prompt via `confirmModulesPurge=false`. Adds a regression test for the non-TTY flow. - Fixed false "Command not found" errors on Windows when a command exists in PATH but exits with a non-zero code. Also fixed path resolution for `--filter` contexts where the command runs in a different package directory. - When a pnpm-lock.yaml contains two documents, ignore the first one. pnpm v11 will write two lockfile documents into pnpm-lock.yaml in order to store pnpm version integrities and config dependency resolutions. - Fixed a bug preventing the `clearCache` function returned by `createNpmResolver` from properly clearing metadata cache. <!-- 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 --> ### [`v10.32.1`](https://github.com/pnpm/pnpm/releases/tag/v10.32.1): pnpm 10.32.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.32.0...v10.32.1) ##### Patch Changes - Fix a regression where `pnpm-workspace.yaml` without a `packages` field caused all directories to be treated as workspace projects. This broke projects that use `pnpm-workspace.yaml` only for settings (e.g. `minimumReleaseAge`) without defining workspace packages [#&#8203;10909](https://github.com/pnpm/pnpm/issues/10909). <!-- 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 --> ### [`v10.32.0`](https://github.com/pnpm/pnpm/releases/tag/v10.32.0): pnpm 10.32 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.31.0...v10.32.0) ##### Minor Changes - Added `--all` flag to `pnpm approve-builds` that approves all pending builds without interactive prompts [#&#8203;10136](https://github.com/pnpm/pnpm/issues/10136). ##### Patch Changes - Reverted change related to setting explicitly the npm config file path, which caused regressions. - Reverted fix related to `lockfile-include-tarball-url`. Fixes [#&#8203;10915](https://github.com/pnpm/pnpm/issues/10915). <!-- 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 --> ### [`v10.31.0`](https://github.com/pnpm/pnpm/releases/tag/v10.31.0): pnpm 10.31 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.30.3...v10.31.0) ##### Minor Changes - When pnpm updates the `pnpm-workspace.yaml`, comments, string formatting, and whitespace will be preserved. ##### Patch Changes - Added `-F` as a short alias for the `--filter` option in the help output. - Handle undefined pkgSnapshot in `pnpm why -r` [#&#8203;10700](https://github.com/pnpm/pnpm/issues/10700). - Fix headless install not being used when a project has an injected self-referencing `file:` dependency that resolves to `link:` in the lockfile. - Fixed a race condition when multiple worker threads import the same package to the global virtual store concurrently. The rename operation now tolerates `ENOTEMPTY`/`EEXIST` errors if another thread already completed the import. - When `lockfile-include-tarball-url` is set to `false`, tarball URLs are now always excluded from the lockfile. Previously, tarball URLs could still appear for packages hosted under non-standard URLs, making the behavior flaky and inconsistent [#&#8203;6667](https://github.com/pnpm/pnpm/issues/6667). - Fixed `optimisticRepeatInstall` skipping install when `overrides`, `packageExtensions`, `ignoredOptionalDependencies`, `patchedDependencies`, or `peersSuffixMaxLength` changed. - Fixed `pnpm patch-commit` failing with "unable to access '/.config/git/attributes': Permission denied" error in environments where HOME is unset or non-standard (Docker containers, CI systems). The issue occurred because pnpm was setting `HOME` and the Windows user profile env var to empty strings to suppress user git configuration when running `git diff`. This caused git to resolve the home directory (`~`) as root (`/`), leading to permission errors when attempting to access `/.config/git/attributes`. Now uses `GIT_CONFIG_GLOBAL: os.devNull` instead, which is git's proper mechanism for bypassing user-level configuration without corrupting the home directory path resolution. Fixes [#&#8203;6537](https://github.com/pnpm/pnpm/issues/6537) - Fix `pnpm why -r --parseable` missing dependents when multiple workspace packages share the same dependency [#&#8203;8100](https://github.com/pnpm/pnpm/issues/8100). - Fix `link-workspace-packages=true` incorrectly linking workspace packages when the requested version doesn't match the workspace package's version. Previously, on fresh installs the version constraint is overridden to `*` in the fallback resolution paths, causing any workspace package with a matching name to be linked regardless of version [#&#8203;10173](https://github.com/pnpm/pnpm/issues/10173). - Fixed `pnpm update --interactive` table breaking with long version strings (e.g., prerelease versions like `7.0.0-dev.20251209.1`) by dynamically calculating column widths instead of using hardcoded values [#&#8203;10316](https://github.com/pnpm/pnpm/issues/10316). - Explicitly tell `npm` the path to the global `rc` config file. - The parameter set by the `--allow-build` flag is written to `allowBuilds`. - Fix a bug in which specifying `filter` on `pnpm-workspace.yaml` would cause pnpm to not detect any projects. - Print help message on running pnpm dlx without arguments and exit. <!-- 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 --> ### [`v10.30.3`](https://github.com/pnpm/pnpm/releases/tag/v10.30.3): pnpm 10.30.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.30.2...v10.30.3) ##### Patch Changes - Fixed version switching via `packageManager` field failing when pnpm is installed as a standalone executable in environments without a system Node.js [#&#8203;10687](https://github.com/pnpm/pnpm/issues/10687). ##### 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> ### [`v10.30.2`](https://github.com/pnpm/pnpm/releases/tag/v10.30.2): pnpm 10.30.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.30.1...v10.30.2) ##### Patch Changes - Fix auto-installed peer dependencies ignoring overrides when a stale version exists in the lockfile. - Fixed "input line too long" error on Windows when running lifecycle scripts with the global virtual store enabled [#&#8203;10673](https://github.com/pnpm/pnpm/pull/10673). - Update [@&#8203;zkochan/js-yaml](https://github.com/zkochan/js-yaml) to fix moderate vulnerability. ##### 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> ### [`v10.30.1`](https://github.com/pnpm/pnpm/releases/tag/v10.30.1): pnpm 10.30.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.30.0...v10.30.1) ##### Patch Changes - Use the `/-/npm/v1/security/audits/quick` endpoint as the primary audit endpoint, falling back to `/-/npm/v1/security/audits` when it fails [#&#8203;10649](https://github.com/pnpm/pnpm/issues/10649). ##### 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> ### [`v10.30.0`](https://github.com/pnpm/pnpm/releases/tag/v10.30.0): pnpm 10.30 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.29.3...v10.30.0) ##### Minor Changes - `pnpm why` now 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. ##### Patch Changes - Revert `pnpm why` dependency pruning to prefer correctness over memory consumption. Reverted PR: [#&#8203;7122](https://github.com/pnpm/pnpm/pull/7122). - Optimize `pnpm why` and `pnpm list` performance in workspaces with many importers by sharing the dependency graph and materialization cache across all importers instead of rebuilding them independently for each one [#&#8203;10596](https://github.com/pnpm/pnpm/pull/10596/changes). ##### 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> ### [`v10.29.3`](https://github.com/pnpm/pnpm/releases/tag/v10.29.3): pnpm 10.29.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.29.2...v10.29.3) ##### Patch Changes - Fixed an out-of-memory error in `pnpm list` (and `pnpm why`) on large dependency graphs by replacing the recursive tree builder with a two-phase approach: a BFS dependency graph followed by cached tree materialization. Duplicate subtrees are now deduplicated in the output, shown as "deduped (N deps hidden)" [#&#8203;10586](https://github.com/pnpm/pnpm/pull/10586). - Fixed `allowBuilds` not working when set via `.pnpmfile.cjs` [#&#8203;10516](https://github.com/pnpm/pnpm/issues/10516). - When the [`enableGlobalVirtualStore`](https://pnpm.io/settings#enableglobalvirtualstore) option is set, the `pnpm deploy` command would incorrectly create symlinks to the global virtual store. To keep the deploy directory self-contained, `pnpm deploy` now ignores this setting and always creates a localized virtual store within the deploy directory. - Fixed `minimumReleaseAgeExclude` not being respected by `pnpm dlx` [#&#8203;10338](https://github.com/pnpm/pnpm/issues/10338). ##### 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> ### [`v10.29.2`](https://github.com/pnpm/pnpm/releases/tag/v10.29.2): pnpm 10.29.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.29.1...v10.29.2) ##### Patch Changes - Reverted a fix shipped in v10.29.1, which caused another issue [#&#8203;10571](https://github.com/pnpm/pnpm/issues/10571). Reverted fix: Fixed pnpm run -r failing with "No projects matched the filters" when an empty pnpm-workspace.yaml exists [#&#8203;10497](https://github.com/pnpm/pnpm/issues/10497). ##### 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> ### [`v10.29.1`](https://github.com/pnpm/pnpm/releases/tag/v10.29.1): pnpm 10.29.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.28.2...v10.29.1) ##### Minor Changes - The `pnpm dlx` / `pnpx` command now supports the `catalog:` protocol. Example: `pnpm dlx shx@catalog:`. - Support configuring `auditLevel` in the `pnpm-workspace.yaml` file [#&#8203;10540](https://github.com/pnpm/pnpm/issues/10540). - Support bare `workspace:` protocol without version specifier. It is now treated as `workspace:*` and resolves to the concrete version during publish [#&#8203;10436](https://github.com/pnpm/pnpm/pull/10436). ##### Patch Changes - Fixed `pnpm list --json` returning incorrect paths when using global virtual store [#&#8203;10187](https://github.com/pnpm/pnpm/issues/10187). - Fix `pnpm store path` and `pnpm store status` using workspace root for path resolution when `storeDir` is relative [#&#8203;10290](https://github.com/pnpm/pnpm/issues/10290). - Fixed `pnpm run -r` failing with "No projects matched the filters" when an empty `pnpm-workspace.yaml` exists [#&#8203;10497](https://github.com/pnpm/pnpm/issues/10497). - Fixed a bug where `catalogMode: strict` would write the literal string `"catalog:"` to `pnpm-workspace.yaml` instead of the resolved version specifier when re-adding an existing catalog dependency [#&#8203;10176](https://github.com/pnpm/pnpm/issues/10176). - Fixed the documentation URL shown in `pnpm completion --help` to point to the correct page at <https://pnpm.io/completion> [#&#8203;10281](https://github.com/pnpm/pnpm/issues/10281). - Skip local `file:` protocol dependencies during `pnpm fetch`. This fixes an issue where `pnpm fetch` would fail in Docker builds when local directory dependencies were not available [#&#8203;10460](https://github.com/pnpm/pnpm/issues/10460). - Fixed `pnpm audit --json` to respect the `--audit-level` setting for both exit code and output filtering [#&#8203;10540](https://github.com/pnpm/pnpm/issues/10540). - update tar to version 7.5.7 to fix security issue Updating the version of dependency tar to 7.5.7 because the previous one have a security vulnerability reported here: <a href="https://github.com/advisories/GHSA-34x7-hfp2-rc4v">CVE-2026-24842</a> - Fix `pnpm audit --fix` replacing reference overrides (e.g. `$foo`) with concrete versions [#&#8203;10325](https://github.com/pnpm/pnpm/issues/10325). - Fix `shamefullyHoist` set via `updateConfig` in `.pnpmfile.cjs` not being converted to `publicHoistPattern` [#&#8203;10271](https://github.com/pnpm/pnpm/issues/10271). - `pnpm help` should correctly report if the currently running pnpm CLI is bundled with Node.js [#&#8203;10561](https://github.com/pnpm/pnpm/issues/10561). - Add a warning when the current directory contains the PATH delimiter character. On macOS, folder names containing forward slashes (/) appear as colons (:) at the Unix layer. Since colons are PATH separators in POSIX systems, this breaks PATH injection for `node_modules/.bin`, causing binaries to not be found when running commands like `pnpm exec` [#&#8203;10457](https://github.com/pnpm/pnpm/issues/10457). ##### 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> ### [`v10.28.2`](https://github.com/pnpm/pnpm/releases/tag/v10.28.2): pnpm 10.28.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.28.1...v10.28.2) ##### Patch Changes - Security fix: prevent path traversal in `directories.bin` field. - When pnpm installs a `file:` or `git:` dependency, it now validates that symlinks point within the package directory. Symlinks to paths outside the package root are skipped to prevent local data from being leaked into `node_modules`. This fixes a security issue where a malicious package could create symlinks to sensitive files (e.g., `/etc/passwd`, `~/.ssh/id_rsa`) and have their contents copied when the package is installed. Note: This only affects `file:` and `git:` dependencies. Registry packages (npm) have symlinks stripped during publish and are not affected. - Fixed optional dependencies to request full metadata from the registry to get the `libc` field, which is required for proper platform compatibility checks [#&#8203;9950](https://github.com/pnpm/pnpm/issues/9950). ##### 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> ### [`v10.28.1`](https://github.com/pnpm/pnpm/releases/tag/v10.28.1): pnpm 10.28.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.28.0...v10.28.1) ##### Patch Changes - Fixed installation of config dependencies from private registries. Added support for object type in `configDependencies` when the tarball URL returned from package metadata differs from the computed URL [#&#8203;10431](https://github.com/pnpm/pnpm/pull/10431). - Fix path traversal vulnerability in binary fetcher ZIP extraction - Validate ZIP entry paths before extraction to prevent writing files outside target directory - Validate BinaryResolution.prefix (basename) to prevent directory escape via crafted prefix - Both attack vectors now throw `ERR_PNPM_PATH_TRAVERSAL` error - Support plain `http://` and `https://` URLs ending with `.git` as git repository dependencies. Previously, URLs like `https://gitea.example.org/user/repo.git#commit` were not recognized as git repositories because they lacked the `git+` prefix (e.g., `git+https://`). This caused issues when installing dependencies from self-hosted git servers like Gitea or Forgejo that don't provide tarball downloads. Changes: - The git resolver now runs before the tarball resolver, ensuring git URLs are handled by the correct resolver - The git resolver now recognizes plain `http://` and `https://` URLs ending in `.git` as git repositories - Removed the `isRepository` check from the tarball resolver since it's no longer needed with the new resolver order Fixes [#&#8203;10468](https://github.com/pnpm/pnpm/issues/10468) - `pnpm run -r` and `pnpm run --filter` now fail with a non-zero exit code when no packages have the specified script. Previously, this only failed when all packages were selected. Use `--if-present` to suppress this error [#&#8203;6844](https://github.com/pnpm/pnpm/issues/6844). - Fixed a path traversal vulnerability in tarball extraction on Windows. The path normalization was only checking for `./` but not `.\`. Since backslashes are directory separators on Windows, malicious packages could use paths like `foo\..\..\.npmrc` to write files outside the package directory. - When running "pnpm exec" from a subdirectory of a project, don't change the current working directory to the root of the project [#&#8203;5759](https://github.com/pnpm/pnpm/issues/5759). - Fixed a path traversal vulnerability in pnpm's bin linking. Bin names starting with `@` bypassed validation, and after scope normalization, path traversal sequences like `../../` remained intact. - Revert Try to avoid making network calls with preferOffline [#&#8203;10334](https://github.com/pnpm/pnpm/pull/10334). - Fix `--save-peer` to write valid semver ranges to `peerDependencies` for protocol-based installs (e.g. `jsr:`) by deriving from resolved versions when available and falling back to `*` if none is available [#&#8203;10417](https://github.com/pnpm/pnpm/issues/10417). - Do not exclude the root workspace project, when it is explicitly selected via a filter [#&#8203;10465](https://github.com/pnpm/pnpm/pull/10465). ##### 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> ### [`v10.28.0`](https://github.com/pnpm/pnpm/releases/tag/v10.28.0): pnpm 10.28 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.27.0...v10.28.0) ##### Minor Changes - Add support for a hook called `beforePacking` that can be used to customize the `package.json` contents at publish time [#&#8203;3816](https://github.com/pnpm/pnpm/issues/3816). - In some cases, a filtered install (i.e. `pnpm install --filter ...`) was slower than running `pnpm install` without any filter arguments. This performance regression is now fixed. Filtered installs should be as fast or faster than a full install [#&#8203;10408](https://github.com/pnpm/pnpm/pull/10408). ##### Patch Changes - Do not add a symlink to the project into the store's project registry if the store is in a subdirectory of the project [#&#8203;10411](https://github.com/pnpm/pnpm/issues/10411). - It should be possible to declare the `requiredScripts` setting in `pnpm-workspace.yaml` [#&#8203;10261](https://github.com/pnpm/pnpm/issues/10261). ##### 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> ### [`v10.27.0`](https://github.com/pnpm/pnpm/releases/tag/v10.27.0): pnpm 10.27 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.26.2...v10.27.0) ##### Minor Changes - Adding `trustPolicyIgnoreAfter` allows you to ignore trust policy checks for packages published more than a specified time ago[#&#8203;10352](https://github.com/pnpm/pnpm/issues/10352). - Added project registry for global virtual store prune support. Projects using the store are now registered via symlinks in `{storeDir}/v10/projects/`. This enables `pnpm store prune` to track which packages are still in use by active projects and safely remove unused packages from the global virtual store. - **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. - Added mark-and-sweep garbage collection for global virtual store. `pnpm store prune` now removes unused packages from the global virtual store's `links/` directory. The algorithm: 1. Scans all registered projects for symlinks pointing to the store 2. Walks transitive dependencies to mark reachable packages 3. Removes any package directories not marked as reachable This includes support for workspace monorepos - all `node_modules` directories within a project (including those in workspace packages) are scanned. ##### Patch Changes - Throw an error if the value of the `tokenHelper` or `<url>:tokenHelper` setting contains an environment variable. - Git dependencies with build scripts should respect the `dangerouslyAllowAllBuilds` settings [#&#8203;10376](https://github.com/pnpm/pnpm/issues/10376). - Skip the package manager check when running with --global and a project packageManager is configured, and warn that the check is skipped. - `pnpm store prune` should not fail if the dlx cache directory has files, not only directories [#&#8203;10384](https://github.com/pnpm/pnpm/pull/10384) - Fixed a bug ([#&#8203;9759](https://github.com/pnpm/pnpm/issues/9759)) where `pnpm add` would incorrectly modify a catalog entry in `pnpm-workspace.yaml` to its exact version. ##### 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> ### [`v10.26.2`](https://github.com/pnpm/pnpm/releases/tag/v10.26.2): pnpm 10.26.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.26.1...v10.26.2) ##### Patch Changes - Improve error message when a package version exists but does not meet the `minimumReleaseAge` constraint. The error now clearly states that the version exists and shows a human-readable time since release (e.g., "released 6 hours ago") [#&#8203;10307](https://github.com/pnpm/pnpm/issues/10307). - Fix installation of Git dependencies using annotated tags [#&#8203;10335](https://github.com/pnpm/pnpm/issues/10335). Previously, pnpm would store the annotated tag object's SHA in the lockfile instead of the actual commit SHA. This caused `ERR_PNPM_GIT_CHECKOUT_FAILED` errors because the checked-out commit hash didn't match the stored tag object hash. - Binaries of runtime engines (Node.js, Deno, Bun) are written to `node_modules/.bin` before lifecycle scripts (install, postinstall, prepare) are executed [#&#8203;10244](https://github.com/pnpm/pnpm/issues/10244). - Try to avoid making network calls with preferOffline [#&#8203;10334](https://github.com/pnpm/pnpm/pull/10334). ##### 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> ### [`v10.26.1`](https://github.com/pnpm/pnpm/releases/tag/v10.26.1): pnpm 10.26.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.26.0...v10.26.1) ##### Patch Changes - Don't fail on `pnpm add`, when `blockExoticSubdeps` is set to `true` [#&#8203;10324](https://github.com/pnpm/pnpm/issues/10324). - Always resolve git references to full commits and ensure `HEAD` points to the commit after checkout [#&#8203;10310](https://github.com/pnpm/pnpm/pull/10310). ##### 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> ### [`v10.26.0`](https://github.com/pnpm/pnpm/releases/tag/v10.26.0): pnpm 10.26 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.25.0...v10.26.0) ##### Minor Changes - **Semi-breaking.** Block git-hosted dependencies from running prepare scripts unless explicitly allowed in `onlyBuiltDependencies` [#&#8203;10288](https://github.com/pnpm/pnpm/pull/10288). - **Semi-breaking.** Compute integrity hash for HTTP tarball dependencies when fetching, storing it in the lockfile to prevent servers from serving altered content on subsequent installs [#&#8203;10287](https://github.com/pnpm/pnpm/pull/10287). - Added a new setting `blockExoticSubdeps` that prevents the resolution of exotic protocols in transitive dependencies. When set to `true`, direct dependencies (those listed in your root `package.json`) may still use exotic sources, but all transitive dependencies must be resolved from a trusted source. Trusted sources include the configured registry, local file paths, workspace links, trusted GitHub repositories (node, bun, deno), and custom resolvers. This helps to secure the dependency supply chain. Packages from trusted sources are considered safer, as they are typically subject to more reliable verification and scanning for malware and vulnerabilities. **Exotic sources** are dependency locations that bypass the usual trusted resolution process. These protocols are specifically targeted and blocked: Git repositories (`git+ssh://...`) and direct URL links to tarballs (`https://.../package.tgz`). Related PR: [#&#8203;10265](https://github.com/pnpm/pnpm/pull/10265). - Added support for `allowBuilds`, which is a new field that can be used instead of `onlyBuiltDependencies` and `ignoredBuiltDependencies`. The new `allowBuilds` field in your `pnpm-workspace.yaml` uses a map of package matchers to explicitly allow (`true`) or disallow (`false`) script execution. This allows for a single, easy-to-manage source of truth for your build permissions. **Example Usage.** To explicitly allow all versions of `esbuild` to run scripts and prevent `core-js` from running them: ```yaml allowBuilds: esbuild: true core-js: false ``` The example above achieves the same result as the previous configuration: ```yaml onlyBuiltDependencies: - esbuild ignoredBuiltDependencies: - core-js ``` Related PR: [#&#8203;10311](https://github.com/pnpm/pnpm/pull/10311) - Added support for `--dry-run` to the `pack` command [#&#8203;10301](https://github.com/pnpm/pnpm/issues/10301). ##### Patch Changes - Show deprecation in table/list formats when latest version is deprecated [#&#8203;8658](https://github.com/pnpm/pnpm/issues/8658). - Remove the `injectWorkspacePackages` setting from the lockfile on the `deploy` command [#&#8203;10294](https://github.com/pnpm/pnpm/pull/10294). - Normalize the tarball URLs before saving them to the lockfile. URLs should not contain default ports, like :80 for http and :443 for https [#&#8203;10273](https://github.com/pnpm/pnpm/pull/10273). - When a dependency is installed via a direct URL that redirects to another URL and is immutable, the original URL is normalized and saved to `package.json` [#&#8203;10197](https://github.com/pnpm/pnpm/pull/10197). ##### 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> ### [`v10.25.0`](https://github.com/pnpm/pnpm/releases/tag/v10.25.0): pnpm 10.25 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.24.0...v10.25.0) ##### Minor Changes - Allow loading certificates from `cert`, `ca`, and `key` for specific registry URLs. E.g., `//registry.example.com/:ca=-----BEGIN CERTIFICATE-----...`. Previously this was only working via `certfile`, `cafile`, and `keyfile`. These properties are supported in `.npmrc`, but were ignored by pnpm, this will make pnpm read and use them as well. Related PR: [#&#8203;10230](https://github.com/pnpm/pnpm/pull/10230). - Added a new flag called `--bare` to `pnpm init` for creating a package.json with the bare minimum of required fields [#&#8203;10226](https://github.com/pnpm/pnpm/issues/10226). ##### Patch Changes - Improved reporting of ignored dependency scripts [#&#8203;10276](https://github.com/pnpm/pnpm/pull/10276). - `pnpm install` should build any dependencies that were added to `onlyBuiltDependencies` and were not built yet [#&#8203;10256](https://github.com/pnpm/pnpm/pull/10256). - `pnpm publish -r --force` should allow to run publish over already existing versions in the registry [#&#8203;10272](https://github.com/pnpm/pnpm/issues/10272). - Don't fail with a `ERR_PNPM_MISSING_TIME` error if a package that is excluded from trust policy checks is missing the time field in the metadata. ##### 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> ### [`v10.24.0`](https://github.com/pnpm/pnpm/releases/tag/v10.24.0): pnpm 10.24 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.23.0...v10.24.0) ##### Minor Changes - Increased network concurrency on machines with many CPU cores. pnpm now automatically selects a network concurrency between 16 and 64, based on the number of pnpm workers (calculated as workers × 3). This improves performance on high-core systems [#&#8203;10068](https://github.com/pnpm/pnpm/issues/10068). ##### Patch Changes - `trustPolicy` should ignore the trust evidences of prerelease versions, when installing a non-prerelease version. - Handle ENOENT errors thrown by `fs.linkSync()`, which can occur in containerized environments (OverlayFS) instead of EXDEV. The operation now gracefully falls back to `fs.copyFileSync()` in these cases [#&#8203;10217](https://github.com/pnpm/pnpm/issues/10217). - Reverted: `pnpm self-update` should download pnpm from the configured npm registry [#&#8203;10205](https://github.com/pnpm/pnpm/pull/10205). - Packages that don't have a `package.json` file (like Node.js) should not be reimported from the store on every install. Another file from the package should be checked in order to verify its presence in `node_modules`. - Correctly read auth tokens for URLs that contain underscores [#&#8203;17](https://github.com/pnpm/npm-conf/pull/17). ##### 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> ### [`v10.23.0`](https://github.com/pnpm/pnpm/releases/tag/v10.23.0): pnpm 10.23 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.22.0...v10.23.0) ##### Minor Changes - Added `--lockfile-only` option to `pnpm list` [#&#8203;10020](https://github.com/pnpm/pnpm/issues/10020). ##### Patch Changes - `pnpm self-update` should download pnpm from the configured npm registry [#&#8203;10205](https://github.com/pnpm/pnpm/pull/10205). - `pnpm self-update` should always install the non-executable pnpm package (pnpm in the registry) and never the `@pnpm/exe` package, when installing v11 or newer. We currently cannot ship `@pnpm/exe` as `pkg` doesn't work with ESM [#&#8203;10190](https://github.com/pnpm/pnpm/pull/10190). - Node.js runtime is not added to "dependencies" on `pnpm add`, if there's a `engines.runtime` setting declared in `package.json` [#&#8203;10209](https://github.com/pnpm/pnpm/issues/10209). - The installation should fail if an optional dependency cannot be installed due to a trust policy check failure [#&#8203;10208](https://github.com/pnpm/pnpm/issues/10208). - `pnpm list` and `pnpm why` now display npm: protocol for aliased packages (e.g., `foo npm:is-odd@3.0.1`) [#&#8203;8660](https://github.com/pnpm/pnpm/issues/8660). - Don't add an extra slash to the Node.js mirror URL [#&#8203;10204](https://github.com/pnpm/pnpm/pull/10204). - `pnpm store prune` should not fail if the store contains Node.js packages [#&#8203;10131](https://github.com/pnpm/pnpm/issues/10131). ##### 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> ### [`v10.22.0`](https://github.com/pnpm/pnpm/releases/tag/v10.22.0): pnpm 10.22 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.21.0...v10.22.0) ##### Minor Changes - Added support for `trustPolicyExclude` [#&#8203;10164](https://github.com/pnpm/pnpm/issues/10164). You can now list one or more specific packages or versions that pnpm should allow to install, even if those packages don't satisfy the trust policy requirement. For example: ```yaml trustPolicy: no-downgrade trustPolicyExclude: - chokidar@4.0.3 - webpack@4.47.0 || 5.102.1 ``` - Allow to override the `engines` field on publish by the `publishConfig.engines` field. ##### Patch Changes - Don't crash when two processes of pnpm are hardlinking the contents of a directory to the same destination simultaneously [#&#8203;10179](https://github.com/pnpm/pnpm/issues/10179). ##### 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> ### [`v10.21.0`](https://github.com/pnpm/pnpm/releases/tag/v10.21.0): pnpm 10.21 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.20.0...v10.21.0) ##### Minor Changes - **Node.js Runtime Installation for Dependencies.** 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 "engines" field. For example: ```json { "engines": { "runtime": { "name": "node", "version": "^24.11.0", "onFail": "download" } } } ``` If the package with the Node.js runtime dependency is a CLI app, pnpm will bind the CLI app to the required Node.js version. This ensures that, regardless of the globally installed Node.js instance, the CLI will use the compatible version of Node.js. If the package has a `postinstall` script, that script will be executed using the specified Node.js version. Related PR: [#&#8203;10141](https://github.com/pnpm/pnpm/pull/10141) - Added a new setting: `trustPolicy`. When set to `no-downgrade`, pnpm will fail installation if a package’s trust level has decreased compared to previous releases — for example, if it was previously published by a trusted publisher but now only has provenance or no trust evidence. This helps prevent installing potentially compromised versions of a package. Related issue: [#&#8203;8889](https://github.com/pnpm/pnpm/issues/8889). - Added support for `pnpm config get globalconfig` to retrieve the global config file path [#&#8203;9977](https://github.com/pnpm/pnpm/issues/9977). ##### Patch Changes - When a user runs `pnpm update` on a dependency that is not directly listed in `package.json`, none of the direct dependencies should be updated [#&#8203;10155](https://github.com/pnpm/pnpm/pull/10155). - Don't crash when two processes of pnpm are hardlinking the contents of a directory to the same destination simultaneously [#&#8203;10160](https://github.com/pnpm/pnpm/pull/10160). - Setting `gitBranchLockfile` and related settings via `pnpm-workspace.yaml` should work [#&#8203;9651](https://github.com/pnpm/pnpm/issues/9651). ##### 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> ### [`v10.20.0`](https://github.com/pnpm/pnpm/releases/tag/v10.20.0): pnpm 10.20 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.19.0...v10.20.0) ##### Minor Changes - Support `--all` option in `pnpm --help` to list all commands [#&#8203;8628](https://github.com/pnpm/pnpm/pull/8628). ##### Patch Changes - When the `latest` version doesn't satisfy the maturity requirement configured by `minimumReleaseAge`, pick the highest version that is mature enough, even if it has a different major version [#&#8203;10100](https://github.com/pnpm/pnpm/issues/10100). - `create` command should not verify patch info. - Set `managePackageManagerVersions` to `false`, when switching to a different version of pnpm CLI, in order to avoid subsequent switches [#&#8203;10063](https://github.com/pnpm/pnpm/issues/10063). ##### 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> ### [`v10.19.0`](https://github.com/pnpm/pnpm/releases/tag/v10.19.0): pnpm 10.19 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.18.3...v10.19.0) ##### Minor Changes - You can now allow specific versions of dependencies to run postinstall scripts. `onlyBuiltDependencies` now accepts package names with lists of trusted versions. For example: ```yaml onlyBuiltDependencies: - nx@21.6.4 || 21.6.5 - esbuild@0.25.1 ``` Related PR: [#&#8203;10104](https://github.com/pnpm/pnpm/pull/10104). - Added support for exact versions in `minimumReleaseAgeExclude` [#&#8203;9985](https://github.com/pnpm/pnpm/issues/9985). You can now list one or more specific versions that pnpm should allow to install, even if those versions don’t satisfy the maturity requirement set by `minimumReleaseAge`. For example: ```yaml minimumReleaseAge: 1440 minimumReleaseAgeExclude: - nx@21.6.5 - webpack@4.47.0 || 5.102.1 ``` ##### 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> ### [`v10.18.3`](https://github.com/pnpm/pnpm/releases/tag/v10.18.3): pnpm 10.18.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.18.2...v10.18.3) ##### Patch Changes - Fix a bug where pnpm would infinitely recurse when using `verifyDepsBeforeInstall: install` and pre/post install scripts that called other pnpm scripts [#&#8203;10060](https://github.com/pnpm/pnpm/issues/10060). - Fixed scoped registry keys (e.g., `@scope:registry`) being parsed as property paths in `pnpm config get` when `--location=project` is used [#&#8203;9362](https://github.com/pnpm/pnpm/issues/9362). - Remove pnpm-specific CLI options before passing to npm publish to prevent "Unknown cli config" warnings [#&#8203;9646](https://github.com/pnpm/pnpm/issues/9646). - Fixed EISDIR error when bin field points to a directory [#&#8203;9441](https://github.com/pnpm/pnpm/issues/9441). - Preserve version and hasBin for variations packages [#&#8203;10022](https://github.com/pnpm/pnpm/issues/10022). - Fixed `pnpm config set --location=project` incorrectly handling keys with slashes (auth tokens, registry settings) [#&#8203;9884](https://github.com/pnpm/pnpm/issues/9884). - When both `pnpm-workspace.yaml` and `.npmrc` exist, `pnpm config set --location=project` now writes to `pnpm-workspace.yaml` (matching read priority) [#&#8203;10072](https://github.com/pnpm/pnpm/issues/10072). - Prevent a table width error in `pnpm outdated --long` [#&#8203;10040](https://github.com/pnpm/pnpm/issues/10040). - Sync bin links after injected dependencies are updated by build scripts. This ensures that binaries created during build processes are properly linked and accessible to consuming projects [#&#8203;10057](https://github.com/pnpm/pnpm/issues/10057). ##### 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> ### [`v10.18.2`](https://github.com/pnpm/pnpm/releases/tag/v10.18.2): pnpm 10.18.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.18.1...v10.18.2) ##### Patch Changes - `pnpm outdated --long` should work [#&#8203;10040](https://github.com/pnpm/pnpm/issues/10040). - Replace ndjson with split2. Reduce the bundle size of pnpm CLI [#&#8203;10054](https://github.com/pnpm/pnpm/pull/10054). - `pnpm dlx` should request the full metadata of packages, when `minimumReleaseAge` is set [#&#8203;9963](https://github.com/pnpm/pnpm/issues/9963). - pnpm version switching should work when the pnpm home directory is in a symlinked directory [#&#8203;9715](https://github.com/pnpm/pnpm/issues/9715). - Fix `EPIPE` errors when piping output to other commands [#&#8203;10027](https://github.com/pnpm/pnpm/issues/10027). ##### 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> ### [`v10.18.1`](https://github.com/pnpm/pnpm/releases/tag/v10.18.1): pnpm 10.18.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.18.0...v10.18.1) ##### Patch Changes - Don't print a warning, when `--lockfile-only` is used [#&#8203;8320](https://github.com/pnpm/pnpm/issues/8320). - `pnpm setup` creates a command shim to the pnpm executable. This is needed to be able to run `pnpm self-update` on Windows [#&#8203;5700](https://github.com/pnpm/pnpm/issues/5700). - When using pnpm catalogs and running a normal `pnpm install`, pnpm produced false positive warnings for "*skip adding to the default catalog because it already exists*". This warning now only prints when using `pnpm add --save-catalog` as originally intended. ##### 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> ### [`v10.18.0`](https://github.com/pnpm/pnpm/releases/tag/v10.18.0): pnpm 10.18 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.17.1...v10.18.0) ##### Minor Changes - Added network performance monitoring to pnpm by implementing warnings for slow network requests, including both metadata fetches and tarball downloads. Added configuration options for warning thresholds: `fetchWarnTimeoutMs` and `fetchMinSpeedKiBps`. Warning messages are displayed when requests exceed time thresholds or fall below speed minimums Related PR: [#&#8203;10025](https://github.com/pnpm/pnpm/pull/10025). ##### Patch Changes - Retry filesystem operations on EAGAIN errors [#&#8203;9959](https://github.com/pnpm/pnpm/pull/9959). - Outdated command respects `minimumReleaseAge` configuration [#&#8203;10030](https://github.com/pnpm/pnpm/pull/10030). - Correctly apply the `cleanupUnusedCatalogs` configuration when removing dependent packages. - Don't fail with a meaningless error when `scriptShell` is set to `false` [#&#8203;8748](https://github.com/pnpm/pnpm/issues/8748). - `pnpm dlx` should not fail when `minimumReleaseAge` is set [#&#8203;10037](https://github.com/pnpm/pnpm/issues/10037). ##### 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> ### [`v10.17.1`](https://github.com/pnpm/pnpm/releases/tag/v10.17.1): pnpm 10.17.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.17.0...v10.17.1) ##### Patch Changes - When a version specifier cannot be resolved because the versions don't satisfy the `minimumReleaseAge` setting, print this information out in the error message [#&#8203;9974](https://github.com/pnpm/pnpm/pull/9974). - Fix `state.json` creation path when executing `pnpm patch` in a workspace project [#&#8203;9733](https://github.com/pnpm/pnpm/pull/9733). - When `minimumReleaseAge` is set and the `latest` tag is not mature enough, prefer a non-deprecated version as the new `latest` [#&#8203;9987](https://github.com/pnpm/pnpm/issues/9987). ##### 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> ### [`v10.17.0`](https://github.com/pnpm/pnpm/releases/tag/v10.17.0): pnpm 10.17 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.16.1...v10.17.0) ##### Minor Changes - The `minimumReleaseAgeExclude` setting now supports patterns. For instance: ```yaml minimumReleaseAge: 1440 minimumReleaseAgeExclude: - "@eslint/*" ``` Related PR: [#&#8203;9984](https://github.com/pnpm/pnpm/pull/9984). ##### Patch Changes - Don't ignore the `minimumReleaseAge` check, when the package is requested by exact version and the packument is loaded from cache [#&#8203;9978](https://github.com/pnpm/pnpm/issues/9978). - When `minimumReleaseAge` is set and the active version under a dist-tag is not mature enough, do not downgrade to a prerelease version in case the original version wasn't a prerelease one [#&#8203;9979](https://github.com/pnpm/pnpm/issues/9979). ##### 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> ### [`v10.16.1`](https://github.com/pnpm/pnpm/releases/tag/v10.16.1): pnpm 10.16.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.16.0...v10.16.1) ##### Patch Changes - The full metadata cache should be stored not at the same location as the abbreviated metadata. This fixes a bug where pnpm was loading the abbreviated metadata from cache and couldn't find the "time" field as a result [#&#8203;9963](https://github.com/pnpm/pnpm/issues/9963). - Forcibly disable ANSI color codes when generating patch diff [#&#8203;9914](https://github.com/pnpm/pnpm/pull/9914). ##### 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> ### [`v10.16.0`](https://github.com/pnpm/pnpm/releases/tag/v10.16.0): pnpm 10.16 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.15.1...v10.16.0) ##### Minor Changes - There have been several incidents recently where popular packages were successfully attacked. To reduce the risk of installing a compromised version, we are introducing a new setting that delays the installation of newly released dependencies. In most cases, such attacks are discovered quickly and the malicious versions are removed from the registry within an hour. The new setting is called `minimumReleaseAge`. It specifies the number of minutes that must pass after a version is published before pnpm will install it. For example, setting `minimumReleaseAge: 1440` ensures that only packages released at least one day ago can be installed. If you set `minimumReleaseAge` but need to disable this restriction for certain dependencies, you can list them under the `minimumReleaseAgeExclude` setting. For instance, with the following configuration pnpm will always install the latest version of webpack, regardless of its release time: ```yaml minimumReleaseAgeExclude: - webpack ``` Related issue: [#&#8203;9921](https://github.com/pnpm/pnpm/issues/9921). - Added support for `finders` [#&#8203;9946](https://github.com/pnpm/pnpm/pull/9946). In the past, `pnpm list` and `pnpm why` could only search for dependencies by **name** (and optionally version). For example: ``` pnpm why minimist ``` prints the chain of dependencies to any installed instance of `minimist`: ``` verdaccio 5.20.1 ├─┬ handlebars 4.7.7 │ └── minimist 1.2.8 └─┬ mv 2.1.1 └─┬ mkdirp 0.5.6 └── minimist 1.2.8 ``` What if we want to search by **other properties** of a dependency, not just its name? For instance, find all packages that have `react@17` in their peer dependencies? This is now possible with "finder functions". Finder functions can be declared in `.pnpmfile.cjs` and invoked with the `--find-by=<function name>` flag when running `pnpm list` or `pnpm why`. Let's say we want to find any dependencies that have React 17 in peer dependencies. We can add this finder to our `.pnpmfile.cjs`: ```js module.exports = { finders: { react17: (ctx) => { return ctx.readManifest().peerDependencies?.react === "^17.0.0"; }, }, }; ``` Now we can use this finder function by running: ``` pnpm why --find-by=react17 ``` pnpm will find all dependencies that have this React in peer dependencies and print their exact locations in the dependency graph. ``` @apollo/client 4.0.4 ├── @graphql-typed-document-node/core 3.2.0 └── graphql-tag 2.12.6 ``` It is also possible to print out some additional information in the output by returning a string from the finder. For example, with the following finder: ```js module.exports = { finders: { react17: (ctx) => { const manifest = ctx.readManifest(); if (manifest.peerDependencies?.react === "^17.0.0") { return `license: ${manifest.license}`; } return false; }, }, }; ``` Every matched package will also print out the license from its `package.json`: ``` @apollo/client 4.0.4 ├── @graphql-typed-document-node/core 3.2.0 │ license: MIT └── graphql-tag 2.12.6 license: MIT ``` ##### Patch Changes - Fix deprecation warning printed when executing pnpm with Node.js 24 [#&#8203;9529](https://github.com/pnpm/pnpm/issues/9529). - Throw an error if `nodeVersion` is not set to an exact semver version [#&#8203;9934](https://github.com/pnpm/pnpm/issues/9934). - `pnpm publish` should be able to publish a `.tar.gz` file [#&#8203;9927](https://github.com/pnpm/pnpm/pull/9927). - Canceling a running process with Ctrl-C should make `pnpm run` return a non-zero exit code [#&#8203;9626](https://github.com/pnpm/pnpm/issues/9626). ##### 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> ### [`v10.15.1`](https://github.com/pnpm/pnpm/releases/tag/v10.15.1): pnpm 10.15.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.15.0...v10.15.1) ##### Patch Changes - Fix `.pnp.cjs` crash when importing subpath [#&#8203;9904](https://github.com/pnpm/pnpm/issues/9904). - When resolving peer dependencies, pnpm looks whether the peer dependency is present in the root workspace project's dependencies. This change makes it so that the peer dependency is correctly resolved even from aliased npm-hosted dependencies or other types of dependencies [#&#8203;9913](https://github.com/pnpm/pnpm/issues/9913). ##### 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> ### [`v10.15.0`](https://github.com/pnpm/pnpm/releases/tag/v10.15.0): pnpm 10.15 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.14.0...v10.15.0) ##### Minor Changes - Added the `cleanupUnusedCatalogs` configuration. When set to `true`, pnpm will remove unused catalog entries during installation [#&#8203;9793](https://github.com/pnpm/pnpm/pull/9793). - Automatically load pnpmfiles from config dependencies that are named `@*/pnpm-plugin-*` [#&#8203;9780](https://github.com/pnpm/pnpm/issues/9780). - `pnpm config get` now prints an INI string for an object value [#&#8203;9797](https://github.com/pnpm/pnpm/issues/9797). - `pnpm config get` now accepts property paths (e.g. `pnpm config get catalog.react`, `pnpm config get .catalog.react`, `pnpm config get 'packageExtensions["@babel/parser"].peerDependencies["@babel/types"]'`), and `pnpm config set` now accepts dot-leading or subscripted keys (e.g. `pnpm config set .ignoreScripts true`). - `pnpm config get --json` now prints a JSON serialization of config value, and `pnpm config set --json` now parses the input value as JSON. ##### Patch Changes - **Semi-breaking.** When automatically installing missing peer dependencies, prefer versions that are already present in the direct dependencies of the root workspace package [#&#8203;9835](https://github.com/pnpm/pnpm/pull/9835). - When executing the `pnpm create` command, must verify whether the node version is supported even if a cache already exists [#&#8203;9775](https://github.com/pnpm/pnpm/pull/9775). - When making requests for the non-abbreviated packument, add `*/*` to the `Accept` header to avoid getting a 406 error on AWS CodeArtifact [#&#8203;9862](https://github.com/pnpm/pnpm/issues/9862). - The standalone exe version of pnpm works with glibc 2.26 again [#&#8203;9734](https://github.com/pnpm/pnpm/issues/9734). - Fix a regression in which `pnpm dlx pkg --help` doesn't pass `--help` to `pkg` [#&#8203;9823](https://github.com/pnpm/pnpm/issues/9823). ##### 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> ### [`v10.14.0`](https://github.com/pnpm/pnpm/releases/tag/v10.14.0): pnpm 10.14 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.13.1...v10.14.0) ##### Minor Changes - **Added support for JavaScript runtime installation** Declare Node.js, Deno, or Bun in [`devEngines.runtime`](https://github.com/openjs-foundation/package-metadata-interoperability-collab-space/issues/15) (inside `package.json`) and let pnpm download and pin it automatically. Usage example: ```jsonc { "devEngines": { "runtime": { "name": "node", "version": "^24.4.0", "onFail": "download" // we only support the "download" value for now } } } ``` How it works: 1. `pnpm install` resolves your specified range to the latest matching runtime version. 2. The exact version (and checksum) is saved in the lockfile. 3. Scripts use the local runtime, ensuring consistency across environments. Why this is better: 1. This new setting supports also Deno and Bun (vs. our Node-only settings `useNodeVersion` and `executionEnv.nodeVersion`) 2. Supports version ranges (not just a fixed version). 3. The resolved version is stored in the pnpm lockfile, along with an integrity checksum for future validation of the Node.js content's validity. 4. It can be used on any workspace project (like `executionEnv.nodeVersion`). So, different projects in a workspace can use different runtimes. 5. For now `devEngines.runtime` setting will install the runtime locally, which we will improve in future versions of pnpm by using a shared location on the computer. Related PR: [#&#8203;9755](https://github.com/pnpm/pnpm/pull/9755). - Add `--cpu`, `--libc`, and `--os` to `pnpm install`, `pnpm add`, and `pnpm dlx` to customize `supportedArchitectures` via the CLI [#&#8203;7510](https://github.com/pnpm/pnpm/issues/7510). ##### Patch Changes - Fix a bug in which `pnpm add` downloads packages whose `libc` differ from `pnpm.supportedArchitectures.libc`. - The integrities of the downloaded Node.js artifacts are verified [#&#8203;9750](https://github.com/pnpm/pnpm/pull/9750). - Allow `dlx` to parse CLI flags and options between the `dlx` command and the command to run or between the `dlx` command and `--` [#&#8203;9719](https://github.com/pnpm/pnpm/issues/9719). - `pnpm install --prod` should removing hoisted dev dependencies [#&#8203;9782](https://github.com/pnpm/pnpm/issues/9782). - Fix an edge case bug causing local tarballs to not re-link into the virtual store. This bug would happen when changing the contents of the tarball without renaming the file and running a filtered install. - Fix a bug causing `pnpm install` to incorrectly assume the lockfile is up to date after changing a local tarball that has peers dependencies. ##### 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> ### [`v10.13.1`](https://github.com/pnpm/pnpm/releases/tag/v10.13.1): pnpm 10.13.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.13.0...v10.13.1) ##### Patch Changes - Run user defined pnpmfiles after pnpmfiles of plugins. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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> ### [`v10.13.0`](https://github.com/pnpm/pnpm/releases/tag/v10.13.0): pnpm 10.13 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.12.4...v10.13.0) ##### Minor Changes - Added the possibility to load multiple pnpmfiles. The `pnpmfile` setting can now accept a list of pnpmfile locations [#&#8203;9702](https://github.com/pnpm/pnpm/pull/9702). - pnpm will now automatically load the `pnpmfile.cjs` file from any [config dependency](https://pnpm.io/config-dependencies) named `@pnpm/plugin-*` or `pnpm-plugin-*` [#&#8203;9729](https://github.com/pnpm/pnpm/pull/9729). The order in which config dependencies are initialized should not matter — they are initialized in alphabetical order. If a specific order is needed, the paths to the `pnpmfile.cjs` files in the config dependencies can be explicitly listed using the `pnpmfile` setting in `pnpm-workspace.yaml`. ##### Patch Changes - When patching dependencies installed via `pkg.pr.new`, treat them as Git tarball URLs [#&#8203;9694](https://github.com/pnpm/pnpm/pull/9694). - Prevent conflicts between local projects' config and the global config in `dangerouslyAllowAllBuilds`, `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, and `neverBuiltDependencies` [#&#8203;9628](https://github.com/pnpm/pnpm/issues/9628). - Sort keys in `pnpm-workspace.yaml` with deep [#&#8203;9701](https://github.com/pnpm/pnpm/pull/9701). - The `pnpm rebuild` command should not add pkgs included in `ignoredBuiltDependencies` to `ignoredBuilds` in `node_modules/.modules.yaml` [#&#8203;9338](https://github.com/pnpm/pnpm/issues/9338). - Replaced `shell-quote` with `shlex` for quoting command arguments [#&#8203;9381](https://github.com/pnpm/pnpm/issues/9381). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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> ### [`v10.12.4`](https://github.com/pnpm/pnpm/releases/tag/v10.12.4): pnpm 10.12.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.12.3...v10.12.4) ##### Patch Changes - Fix `pnpm licenses` command for local dependencies [#&#8203;9583](https://github.com/pnpm/pnpm/pull/9583). - Fix a bug in which `pnpm ls --filter=not-exist --json` prints nothing instead of an empty array [#&#8203;9672](https://github.com/pnpm/pnpm/issues/9672). - Fix a deadlock that sometimes happens during peer dependency resolution [#&#8203;9673](https://github.com/pnpm/pnpm/issues/9673). - Running `pnpm install` after `pnpm fetch` should hoist all dependencies that need to be hoisted. Fixes a regression introduced in [v10.12.2](https://github.com/pnpm/pnpm/releases/tag/v10.12.2) by [#&#8203;9648](https://github.com/pnpm/pnpm/issues/9648); resolves [#&#8203;9689](https://github.com/pnpm/pnpm/issues/9689). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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> ### [`v10.12.3`](https://github.com/pnpm/pnpm/releases/tag/v10.12.3): pnpm 10.12.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.12.2...v10.12.3) ##### Patch Changes - Restore hoisting of optional peer dependencies when installing with an outdated lockfile. Regression introduced in [v10.12.2] by [#&#8203;9648]; resolves [#&#8203;9685]. [v10.12.2]: https://github.com/pnpm/pnpm/releases/tag/v10.12.2 [#&#8203;9648]: https://github.com/pnpm/pnpm/pull/9648 [#&#8203;9685]: https://github.com/pnpm/pnpm/issues/9685 ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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> ### [`v10.12.2`](https://github.com/pnpm/pnpm/releases/tag/v10.12.2): pnpm 10.12.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.12.1...v10.12.2) ##### Patch Changes - Fixed hoisting with `enableGlobalVirtualStore` set to `true` [#&#8203;9648](https://github.com/pnpm/pnpm/pull/9648). - Fix the `--help` and `-h` flags not working as expected for the `pnpm create` command. - The dependency package path output by the `pnpm licenses list --json` command is incorrect. - Fix a bug in which `pnpm deploy` fails due to overridden dependencies having peer dependencies causing `ERR_PNPM_OUTDATED_LOCKFILE` [#&#8203;9595](https://github.com/pnpm/pnpm/issues/9595). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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> ### [`v10.12.1`](https://github.com/pnpm/pnpm/releases/tag/v10.12.1): pnpm 10.12.1 ##### Minor Changes - **Experimental.** Added support for global virtual stores. When enabled, `node_modules` contains only symlinks to a central virtual store, rather than to `node_modules/.pnpm`. By default, this central store is located at `<store-path>/links` (you can find the store path by running `pnpm store path`). In the central virtual store, each package is hard linked into a directory whose name is the hash of its dependency graph. This allows multiple projects on the system to symlink shared dependencies from this central location, significantly improving installation speed when a warm cache is available. > This is conceptually similar to how [NixOS manages packages](https://nixos.org/guides/how-nix-works/), using dependency graph hashes to create isolated and reusable package directories. To enable the global virtual store, set `enableGlobalVirtualStore: true` in your root `pnpm-workspace.yaml`, or globally via: ```sh pnpm config -g set enable-global-virtual-store true ``` NOTE: In CI environments, where caches are typically cold, this setting may slow down installation. pnpm automatically disables the global virtual store when running in CI. Short demo of the speed of installation with this new setting enabled: <https://www.youtube.com/watch?v=pNDFfJvaubY&ab_channel=pnpm> Related PR: [#&#8203;8190](https://github.com/pnpm/pnpm/pull/8190) <!----> - The `pnpm update` command now supports updating `catalog:` protocol dependencies and writes new specifiers to `pnpm-workspace.yaml`. - A new `catalogMode` setting is available for controlling if and how dependencies are added to the default catalog. It can be configured to several modes: - `strict`: Only allows dependency versions from the catalog. Adding a dependency outside the catalog's version range will cause an error. - `prefer`: Prefers catalog versions, but will fall back to direct dependencies if no compatible version is found. - `manual` (default): Does not automatically add dependencies to the catalog. - Added two new CLI options (`--save-catalog` and `--save-catalog-name=<name>`) to `pnpm add` to save new dependencies as catalog entries. `catalog:` or `catalog:<name>` will be added to `package.json` and the package specifier will be added to the `catalogs` or `catalog[<name>]` object in `pnpm-workspace.yaml` [#&#8203;9425](https://github.com/pnpm/pnpm/issues/9425). - **Semi-breaking.** The keys used for side-effects caches have changed. If you have a side-effects cache generated by a previous version of pnpm, the new version will not use it and will create a new cache instead [#&#8203;9605](https://github.com/pnpm/pnpm/pull/9605). - Added a new setting called `ci` for explicitly telling pnpm if the current environment is a CI or not. ##### Patch Changes - Sort versions printed by `pnpm patch` using semantic versioning rules. - Improve the way the error message displays mismatched specifiers. Show differences instead of 2 whole objects [#&#8203;9598](https://github.com/pnpm/pnpm/pull/9598). - Revert [#&#8203;9574](https://github.com/pnpm/pnpm/pull/9574) to fix a regression [#&#8203;9596](https://github.com/pnpm/pnpm/issues/9596). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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> ### [`v10.11.1`](https://github.com/pnpm/pnpm/releases/tag/v10.11.1): pnpm 10.11.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.11.0...v10.11.1) ##### Patch Changes - Fix an issue in which `pnpm deploy --legacy` creates unexpected directories when the root `package.json` has a workspace package as a peer dependency [#&#8203;9550](https://github.com/pnpm/pnpm/issues/9550). - Dependencies specified via a URL that redirects will only be locked to the target if it is immutable, fixing a regression when installing from GitHub releases. ([#&#8203;9531](https://github.com/pnpm/pnpm/issues/9531)) - Installation should not exit with an error if `strictPeerDependencies` is `true` but all issues are ignored by `peerDependencyRules` [#&#8203;9505](https://github.com/pnpm/pnpm/pull/9505). - Use `pnpm_config_` env variables instead of `npm_config_` [#&#8203;9571](https://github.com/pnpm/pnpm/pull/9571). - Fix a regression (in v10.9.0) causing the `--lockfile-only` flag on `pnpm update` to produce a different `pnpm-lock.yaml` than an update without the flag. - Let `pnpm deploy` work in repos with `overrides` when `inject-workspace-packages=true` [#&#8203;9283](https://github.com/pnpm/pnpm/issues/9283). - Fixed the problem of path loss caused by parsing URL address. Fixes a regression shipped in pnpm v10.11 via [#&#8203;9502](https://github.com/pnpm/pnpm/pull/9502). - `pnpm -r --silent run` should not print out section [#&#8203;9563](https://github.com/pnpm/pnpm/issues/9563). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.11.0`](https://github.com/pnpm/pnpm/releases/tag/v10.11.0): pnpm 10.11 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.10.0...v10.11.0) ##### Minor Changes - A new setting added for `pnpm init` to create a `package.json` with `type=module`, when `init-type` is `module`. Works as a flag for the init command too [#&#8203;9463](https://github.com/pnpm/pnpm/pull/9463). - Added support for Nushell to `pnpm setup` [#&#8203;6476](https://github.com/pnpm/pnpm/issues/6476). - Added two new flags to the `pnpm audit` command, `--ignore` and `--ignore-unfixable` [#&#8203;8474](https://github.com/pnpm/pnpm/pull/8474). Ignore all vulnerabilities that have no solution: ```shell > pnpm audit --ignore-unfixable ``` Provide a list of CVE's to ignore those specifically, even if they have a resolution. ```shell > pnpm audit --ignore=CVE-2021-1234 --ignore=CVE-2021-5678 ``` - Added support for recursively running pack in every project of a workspace [#&#8203;4351](https://github.com/pnpm/pnpm/issues/4351). Now you can run `pnpm -r pack` to pack all packages in the workspace. ##### Patch Changes - pnpm version management should work, when `dangerouslyAllowAllBuilds` is set to `true` [#&#8203;9472](https://github.com/pnpm/pnpm/issues/9472). - `pnpm link` should work from inside a workspace [#&#8203;9506](https://github.com/pnpm/pnpm/issues/9506). - Set the default `workspaceConcurrency` to `Math.min(os.availableParallelism(), 4)` [#&#8203;9493](https://github.com/pnpm/pnpm/pull/9493). - Installation should not exit with an error if `strictPeerDependencies` is `true` but all issues are ignored by `peerDependencyRules` [#&#8203;9505](https://github.com/pnpm/pnpm/pull/9505). - Read `updateConfig` from `pnpm-workspace.yaml` [#&#8203;9500](https://github.com/pnpm/pnpm/issues/9500). - Add support for `recursive pack` - Remove `url.parse` usage to fix warning on Node.js 24 [#&#8203;9492](https://github.com/pnpm/pnpm/issues/9492). - `pnpm run` should be able to run commands from the workspace root, if `ignoreScripts` is set tot `true` [#&#8203;4858](https://github.com/pnpm/pnpm/issues/4858). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.10.0`](https://github.com/pnpm/pnpm/releases/tag/v10.10.0): pnpm 10.10 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.9.0...v10.10.0) ##### Minor Changes - Allow loading the `preResolution`, `importPackage`, and `fetchers` hooks from local pnpmfile. ##### Patch Changes - Fix `cd` command, when `shellEmulator` is `true` [#&#8203;7838](https://github.com/pnpm/pnpm/issues/7838). - Sort keys in `pnpm-workspace.yaml` [#&#8203;9453](https://github.com/pnpm/pnpm/pull/9453). - Pass the `npm_package_json` environment variable to the executed scripts [#&#8203;9452](https://github.com/pnpm/pnpm/issues/9452). - Fixed a mistake in the description of the `--reporter=silent` option. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.9.0`](https://github.com/pnpm/pnpm/releases/tag/v10.9.0): pnpm 10.9 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.8.1...v10.9.0) ##### Minor Changes - **Added support for installing JSR packages.** You can now install JSR packages using the following syntax: ``` pnpm add jsr:<pkg_name> ``` or with a version range: ``` pnpm add jsr:<pkg_name>@<range> ``` For example, running: ``` pnpm add jsr:@foo/bar ``` will add the following entry to your `package.json`: ```json { "dependencies": { "@foo/bar": "jsr:^0.1.2" } } ``` When publishing, this entry will be transformed into a format compatible with npm, older versions of Yarn, and previous pnpm versions: ```json { "dependencies": { "@foo/bar": "npm:@jsr/foo__bar@^0.1.2" } } ``` Related issue: [#&#8203;8941](https://github.com/pnpm/pnpm/issues/8941). Note: The `@jsr` scope defaults to <https://npm.jsr.io/> if the `@jsr:registry` setting is not defined. - Added a new setting, `dangerouslyAllowAllBuilds`, for automatically running any scripts of dependencies without the need to approve any builds. It was already possible to allow all builds by adding this to `pnpm-workspace.yaml`: ```yaml neverBuiltDependencies: [] ``` `dangerouslyAllowAllBuilds` has the same effect but also allows to be set globally via: ``` pnpm config set dangerouslyAllowAllBuilds true ``` It can also be set when running a command: ``` pnpm install --dangerously-allow-all-builds ``` ##### Patch Changes - Fix a false negative in `verifyDepsBeforeRun` when `nodeLinker` is `hoisted` and there is a workspace package without dependencies and `node_modules` directory [#&#8203;9424](https://github.com/pnpm/pnpm/issues/9424). - Explicitly drop `verifyDepsBeforeRun` support for `nodeLinker: pnp`. Combining `verifyDepsBeforeRun` and `nodeLinker: pnp` will now print a warning. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.8.1`](https://github.com/pnpm/pnpm/releases/tag/v10.8.1): pnpm 10.8.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.8.0...v10.8.1) ##### Patch Changes - Removed bright white highlighting, which didn't look good on some light themes [#&#8203;9389](https://github.com/pnpm/pnpm/pull/9389). - If there is no pnpm related configuration in `package.json`, `onlyBuiltDependencies` will be written to `pnpm-workspace.yaml` file [#&#8203;9404](https://github.com/pnpm/pnpm/pull/9404). - The patch file path saved by the pnpm `patch-commit` and `patch-remove` commands should be a relative path [#&#8203;9403](https://github.com/pnpm/pnpm/pull/9403). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.8.0`](https://github.com/pnpm/pnpm/releases/tag/v10.8.0): pnpm 10.8 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.7.1...v10.8.0) ##### Minor Changes - **Experimental.** A new hook is supported for updating configuration settings. The hook can be provided via `.pnpmfile.cjs`. For example: ```js module.exports = { hooks: { updateConfig: (config) => ({ ...config, nodeLinker: "hoisted", }), }, }; ``` - Now you can use the `pnpm add` command with the `--config` flag to install new configurational dependencies [#&#8203;9377](https://github.com/pnpm/pnpm/pull/9377). ##### Patch Changes - Do not hang indefinitely, when there is a glob that starts with `!/` in `pnpm-workspace.yaml`. This fixes a regression introduced by [#&#8203;9169](https://github.com/pnpm/pnpm/pull/9169). - `pnpm audit --fix` should update the overrides in `pnpm-workspace.yaml`. - `pnpm link` should update overrides in `pnpm-workspace.yaml`, not in `package.json` [#&#8203;9365](https://github.com/pnpm/pnpm/pull/9365). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.7.1`](https://github.com/pnpm/pnpm/releases/tag/v10.7.1): pnpm 10.7.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.7.0...v10.7.1) ##### Patch Changes - `pnpm config set` should convert the settings to their correct type before adding them to `pnpm-workspace.yaml` [#&#8203;9355](https://github.com/pnpm/pnpm/issues/9355). - `pnpm config get` should read auth related settings via npm CLI [#&#8203;9345](https://github.com/pnpm/pnpm/issues/9345). - Replace leading `~/` in a path in `.npmrc` with the home directory [#&#8203;9217](https://github.com/pnpm/pnpm/issues/9217). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.7.0`](https://github.com/pnpm/pnpm/releases/tag/v10.7.0): pnpm 10.7 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.6.5...v10.7.0) ##### Minor Changes - `pnpm config get` and `list` also show settings set in `pnpm-workspace.yaml` files [#&#8203;9316](https://github.com/pnpm/pnpm/pull/9316). - It should be possible to use env variables in `pnpm-workspace.yaml` setting names and value. - Add an ability to patch dependencies by version ranges. Exact versions override version ranges, which in turn override name-only patches. Version range `*` is the same as name-only, except that patch application failure will not be ignored. For example: ```yaml patchedDependencies: foo: patches/foo-1.patch foo@^2.0.0: patches/foo-2.patch foo@2.1.0: patches/foo-3.patch ``` The above configuration would apply `patches/foo-3.patch` to `foo@2.1.0`, `patches/foo-2.patch` to all `foo` versions which satisfy `^2.0.0` except `2.1.0`, and `patches/foo-1.patch` to the remaining `foo` versions. > \[!WARNING] > The version ranges should not overlap. If you want to specialize a sub range, make sure to exclude it from the other keys. For example: > > ```yaml > # pnpm-workspace.yaml > patchedDependencies: > # the specialized sub range > 'foo@2.2.0-2.8.0': patches/foo.2.2.0-2.8.0.patch > # the more general patch, excluding the sub range above > 'foo@>=2.0.0 <2.2.0 || >2.8.0': 'patches/foo.gte2.patch > ``` > > In most cases, however, it's sufficient to just define an exact version to override the range. - `pnpm config set --location=project` saves the setting to a `pnpm-workspace.yaml` file if no `.npmrc` file is present in the directory [#&#8203;9316](https://github.com/pnpm/pnpm/pull/9316). - Rename `pnpm.allowNonAppliedPatches` to `pnpm.allowUnusedPatches`. The old name is still supported but it would print a deprecation warning message. - Add `pnpm.ignorePatchFailures` to manage whether pnpm would ignore patch application failures. If `ignorePatchFailures` is not set, pnpm would throw an error when patches with exact versions or version ranges fail to apply, and it would ignore failures from name-only patches. If `ignorePatchFailures` is explicitly set to `false`, pnpm would throw an error when any type of patch fails to apply. If `ignorePatchFailures` is explicitly set to `true`, pnpm would print a warning when any type of patch fails to apply. ##### Patch Changes - Remove dependency paths from audit output to prevent out-of-memory errors [#&#8203;9280](https://github.com/pnpm/pnpm/issues/9280). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.6.5`](https://github.com/pnpm/pnpm/releases/tag/v10.6.5): pnpm 10.6.5 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.6.4...v10.6.5) ##### Patch Changes - Remove warnings after having explicitly approved no builds [#&#8203;9296](https://github.com/pnpm/pnpm/issues/9296). - When installing different dependency packages, should retain the `ignoredBuilds` field in the `.modules.yaml` file [#&#8203;9240](https://github.com/pnpm/pnpm/issues/9240). - Fix usages of the [`catalog:` protocol](https://pnpm.io/catalogs) in [injected local workspace packages](https://pnpm.io/package_json#dependenciesmetainjected). This previously errored with `ERR_PNPM_SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER`. [#&#8203;8715](https://github.com/pnpm/pnpm/issues/8715) - Setting `workspace-concurrency` to less than or equal to 0 should work [#&#8203;9297](https://github.com/pnpm/pnpm/issues/9297). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.6.4`](https://github.com/pnpm/pnpm/releases/tag/v10.6.4): pnpm 10.6.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.6.3...v10.6.4) ##### Patch Changes - Fix `pnpm dlx` with `--allow-build` flag [#&#8203;9263](https://github.com/pnpm/pnpm/issues/9263). - Invalid Node.js version in `use-node-version` should not cause pnpm itself to break [#&#8203;9276](https://github.com/pnpm/pnpm/issues/9276). - The max amount of workers running for linking packages from the store has been reduced to 4 to achieve optimal results [#&#8203;9286](https://github.com/pnpm/pnpm/issues/9286). The workers are performing many file system operations, so increasing the number of CPUs doesn't help performance after some point. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.6.3`](https://github.com/pnpm/pnpm/releases/tag/v10.6.3): pnpm 10.6.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.6.2...v10.6.3) ##### Patch Changes - `pnpm install --prod=false` should not crash, when executed in a project with a `pnpm-workspace.yaml` file [#&#8203;9233](https://github.com/pnpm/pnpm/issues/9233). This fixes regression introduced via [#&#8203;9211](https://github.com/pnpm/pnpm/pull/9211). - Add the missing `node-options` config to `recursive run` [#&#8203;9180](https://github.com/pnpm/pnpm/issues/9180). - Removed a branching code path that only executed when `dedupe-peer-dependents=false`. We believe this internal refactor will not result in behavior changes, but we expect it to make future pnpm versions behave more consistently for projects that override `dedupe-peer-dependents` to false. There should be less unique bugs from turning off `dedupe-peer-dependents`. See details in [#&#8203;9259](https://github.com/pnpm/pnpm/pull/9259). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.6.2`](https://github.com/pnpm/pnpm/releases/tag/v10.6.2): pnpm 10.6.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.6.1...v10.6.2) ##### Patch Changes - `pnpm self-update` should always update the version in the `packageManager` field of `package.json`. - Fix running pnpm CLI from pnpm CLI on Windows when the CLI is bundled to an executable [#&#8203;8971](https://github.com/pnpm/pnpm/issues/8971). - `pnpm patch-commit` will now use the same filesystem as the store directory to compare and create patch files. - Don't show info output when `--loglevel=error` is used. - `peerDependencyRules` should be set in `pnpm-workspace.yaml` to take effect. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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?0" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/nx_light.svg?0" /> <img src="https://pnpm.io/img/users/nx.svg" width="70" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.6.1`](https://github.com/pnpm/pnpm/releases/tag/v10.6.1): pnpm 10.6.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.6.0...v10.6.1) ##### Patch Changes - The pnpm CLI process should not stay hanging, when `--silent` reporting is used. - When `--loglevel` is set to `error`, don't show installation summary, execution time, and big tarball download progress. - Don't ignore pnpm.patchedDependencies from `package.json` [#&#8203;9226](https://github.com/pnpm/pnpm/issues/9226). - When executing the `approve-builds` command, if package.json contains `onlyBuiltDependencies` or `ignoredBuiltDependencies`, the selected dependency package will continue to be written into `package.json`. - When a package version cannot be found in the package metadata, print the registry from which the package was fetched. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.6.0`](https://github.com/pnpm/pnpm/releases/tag/v10.6.0): pnpm 10.6 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.5.2...v10.6.0) ##### Minor Changes - `pnpm-workspace.yaml` can now hold all the settings that `.npmrc` accepts. The settings should use camelCase [#&#8203;9211](https://github.com/pnpm/pnpm/pull/9211). `pnpm-workspace.yaml` example: ```yaml verifyDepsBeforeRun: install optimisticRepeatInstall: true publicHoistPattern: - "*types*" - "!@types/react" ``` - Projects using a `file:` dependency on a local tarball file (i.e. `.tgz`, `.tar.gz`, `.tar`) will see a performance improvement during installation. Previously, using a `file:` dependency on a tarball caused the lockfile resolution step to always run. The lockfile will now be considered up-to-date if the tarball is unchanged. ##### Patch Changes - `pnpm self-update` should not leave a directory with a broken pnpm installation if the installation fails. - `fast-glob` replace with `tinyglobby` to reduce the size of the pnpm CLI dependencies [#&#8203;9169](https://github.com/pnpm/pnpm/pull/9169). - `pnpm deploy` should not remove fields from the deployed package's `package.json` file [#&#8203;9215](https://github.com/pnpm/pnpm/issues/9215). - `pnpm self-update` should not read the pnpm settings from the `package.json` file in the current working directory. - Fix `pnpm deploy` creating a `package.json` without the `imports` and `license` field [#&#8203;9193](https://github.com/pnpm/pnpm/issues/9193). - `pnpm update -i` should list only packages that have newer versions [#&#8203;9206](https://github.com/pnpm/pnpm/issues/9206). - Fix a bug causing entries in the `catalogs` section of the `pnpm-lock.yaml` file to be removed when `dedupe-peer-dependents=false` on a filtered install. [#&#8203;9112](https://github.com/pnpm/pnpm/issues/9112) ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://syntax.fm/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/syntaxfm.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/syntaxfm_light.svg" /> <img src="https://pnpm.io/img/users/syntaxfm.svg" width="90" alt="Syntax" /> </picture> </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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://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> </tbody> </table> ### [`v10.5.2`](https://github.com/pnpm/pnpm/releases/tag/v10.5.2): pnpm 10.5.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.5.1...v10.5.2) ##### Patch Changes - The `pnpm config set` command should change the global `.npmrc` file by default. This was a regression introduced by [#&#8203;9151](https://github.com/pnpm/pnpm/pull/9151) and shipped in pnpm v10.5.0. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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> </tr> </tbody> </table> ### [`v10.5.1`](https://github.com/pnpm/pnpm/releases/tag/v10.5.1): pnpm 10.5.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.5.0...v10.5.1) ##### Patch Changes - Throw an error message if a `pnpm-workspaces.yaml` or `pnpm-workspaces.yml` file is found instead of a `pnpm-workspace.yaml` [#&#8203;9170](https://github.com/pnpm/pnpm/issues/9170). - Fix the update of `pnpm-workspace.yaml` by the `pnpm approve-builds` command [#&#8203;9168](https://github.com/pnpm/pnpm/issues/9168). - Normalize generated link paths in `package.json` [#&#8203;9163](https://github.com/pnpm/pnpm/pull/9163) - Specifying `overrides` in `pnpm-workspace.yaml` should work. - `pnpm dlx` should ignore settings from the `package.json` file in the current working directory [#&#8203;9178](https://github.com/pnpm/pnpm/issues/9178). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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> </tr> </tbody> </table> ### [`v10.5.0`](https://github.com/pnpm/pnpm/releases/tag/v10.5.0): pnpm 10.5 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.4.1...v10.5.0) ##### Minor Changes - The `pnpm.*` settings from `package.json` can now be specified in the `pnpm-workspace.yaml` file instead [#&#8203;9121](https://github.com/pnpm/pnpm/pull/9121). `package.json`: ```json { "pnpm": { "onlyBuiltDependencies": ["esbuild", "fuse-native"] } } ``` `pnpm-workspace.yaml`: ```yaml onlyBuiltDependencies: - esbuild - fuse-native ``` - Added support for automatically syncing files of injected workspace packages after `pnpm run` [#&#8203;9081](https://github.com/pnpm/pnpm/issues/9081). Use the `sync-injected-deps-after-scripts` setting to specify which scripts build the workspace package. This tells pnpm when syncing is needed. The setting should be defined in a `.npmrc` file at the root of the workspace. Example: ```ini sync-injected-deps-after-scripts[]=compile ``` - The `packages` field in `pnpm-workspace.yaml` became optional. ##### Patch Changes - `pnpm link` with no parameters should work as if `--global` is specified [#&#8203;9151](https://github.com/pnpm/pnpm/pull/9151). - Allow scope registry CLI option without `--config.` prefix such as `--@scope:registry=https://scope.example.com/npm` [#&#8203;9089](https://github.com/pnpm/pnpm/pull/9089). - `pnpm link <path>` should calculate relative path from the root of the workspace directory [#&#8203;9132](https://github.com/pnpm/pnpm/pull/9132). - Fix a bug causing catalog snapshots to be removed from the `pnpm-lock.yaml` file when using `--fix-lockfile` and `--filter`. [#&#8203;8639](https://github.com/pnpm/pnpm/issues/8639) - Fix a bug causing catalog protocol dependencies to not re-resolve on a filtered install [#&#8203;8638](https://github.com/pnpm/pnpm/issues/8638). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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> </tr> </tbody> </table> ### [`v10.4.1`](https://github.com/pnpm/pnpm/releases/tag/v10.4.1): pnpm 10.4.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.4.0...v10.4.1) ##### Patch Changes - Throws an error when the value provided by the `--allow-build` option overlaps with the `pnpm.ignoredBuildDependencies` list [#&#8203;9105](https://github.com/pnpm/pnpm/pull/9105). - Print pnpm's version after the execution time at the end of the console output. - Print warning about ignored builds of dependencies on repeat install [#&#8203;9106](https://github.com/pnpm/pnpm/issues/9106). - Setting `init-package-manager` should work. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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> </tr> </tbody> </table> ### [`v10.4.0`](https://github.com/pnpm/pnpm/compare/v10.3.0...v10.4.0) [Compare Source](https://github.com/pnpm/pnpm/compare/v10.3.0...v10.4.0) ### [`v10.3.0`](https://github.com/pnpm/pnpm/releases/tag/v10.3.0): pnpm 10.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.2.1...v10.3.0) See [breaking changes in v10](https://github.com/pnpm/pnpm/releases/tag/v10.0.0) ##### Minor Changes - Added a new setting called `strict-dep-builds`. When enabled, the installation will exit with a non-zero exit code if any dependencies have unreviewed build scripts (aka postinstall scripts) [#&#8203;9071](https://github.com/pnpm/pnpm/pull/9071). ##### Patch Changes - Fix a false negative of `verify-deps-before-run` after `pnpm install --production|--no-optional` [#&#8203;9019](https://github.com/pnpm/pnpm/issues/9019). - Print the warning about blocked installation scripts at the end of the installation output and make it more prominent. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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> </tr> </tbody> </table> ### [`v10.2.1`](https://github.com/pnpm/pnpm/releases/tag/v10.2.1): pnpm 10.2.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.2.0...v10.2.1) ##### Patch Changes - Don't read a package from side-effects cache if it isn't allowed to be built [#&#8203;9042](https://github.com/pnpm/pnpm/issues/9042). - `pnpm approve-builds` should work, when executed from a subdirectory of a workspace [#&#8203;9042](https://github.com/pnpm/pnpm/issues/9042). - `pnpm deploy --legacy` should work without injected dependencies. - Add information about how to deploy without "injected dependencies" to the "pnpm deploy" error message. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" 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://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </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="120" alt="Nx" /> </picture> </a> </td> </tr> <tr> <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://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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> </tr> </tbody> </table> ### [`v10.2.0`](https://github.com/pnpm/pnpm/releases/tag/v10.2.0): pnpm 10.2 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.1.0...v10.2.0) See [breaking changes in v10](https://github.com/pnpm/pnpm/releases/tag/v10.0.0) ##### Minor Changes - Packages executed via `pnpm dlx` and `pnpm create` are allowed to be built (run postinstall scripts) by default. If the packages executed by `dlx` or `create` have dependencies that have to be built, they should be listed via the `--allow-build` flag. For instance, if you want to run a package called `bundle` that has `esbuild` in dependencies and want to allow `esbuild` to run postinstall scripts, run: ``` pnpm --allow-build=esbuild dlx bundle ``` Related PR: [#&#8203;9026](https://github.com/pnpm/pnpm/pull/9026). ##### Patch Changes - Quote args for scripts with shell-quote to support new lines (on POSIX only) [#&#8203;8980](https://github.com/pnpm/pnpm/issues/8980). - Fix a bug in which `pnpm deploy` fails to read the correct `projectId` when the deploy source is the same as the workspace directory [#&#8203;9001](https://github.com/pnpm/pnpm/issues/9001). - Proxy settings should be respected, when resolving Git-hosted dependencies [#&#8203;6530](https://github.com/pnpm/pnpm/issues/6530). - Prevent `overrides` from adding invalid version ranges to `peerDependencies` by keeping the `peerDependencies` and overriding them with prod `dependencies` [#&#8203;8978](https://github.com/pnpm/pnpm/issues/8978). - Sort the package names in the "pnpm.onlyBuiltDependencies" list saved by `pnpm approve-builds`. ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://figma.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/figma.svg" width="80" alt="Figma"></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://prisma.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/prisma.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/prisma_light.svg" /> <img src="https://pnpm.io/img/users/prisma.svg" width="180" alt="Prisma" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </picture> </a> </td> </tr> <tr> <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="120" alt="Nx" /> </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> </tr> <tr> <td align="center" valign="middle"> <a href="https://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://canva.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/canva.svg" width="120" alt="Canva" /> </a> </td> </tr> </tbody> </table> ### [`v10.1.0`](https://github.com/pnpm/pnpm/releases/tag/v10.1.0): pnpm 10.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v10.0.0...v10.1.0) See [breaking changes in v10](https://github.com/pnpm/pnpm/releases/tag/v10.0.0) ##### Minor Changes - Added a new command for printing the list of dependencies with ignored build scripts: `pnpm ignored-builds` [#&#8203;8963](https://github.com/pnpm/pnpm/pull/8963). - Added a new command for approving dependencies for running scripts during installation: `pnpm approve-builds` [#&#8203;8963](https://github.com/pnpm/pnpm/pull/8963). - Added a new setting called `optimistic-repeat-install`. When enabled, a fast check will be performed before proceeding to installation. This way a repeat install or an install on a project with everything up-to-date becomes a lot faster. But some edge cases might arise, so we keep it disabled by default for now [#&#8203;8977](https://github.com/pnpm/pnpm/pull/8977). - Added a new field "pnpm.ignoredBuiltDependencies" for explicitly listing packages that should not be built. When a package is in the list, pnpm will not print an info message about that package not being built [#&#8203;8935](https://github.com/pnpm/pnpm/issues/8935). ##### Patch Changes - Verify that the package name is valid when executing the publish command. - When running `pnpm install`, the `preprepare` and `postprepare` scripts of the project should be executed [#&#8203;8989](https://github.com/pnpm/pnpm/pull/8989). - Allow `workspace:` and `catalog:` to be part of wider version range in `peerDependencies`. - `pnpm deploy` should inherit the `pnpm` object from the root `package.json` [#&#8203;8991](https://github.com/pnpm/pnpm/pull/8991). - Make sure that the deletion of a `node_modules` in a sub-project of a monorepo is detected as out-of-date [#&#8203;8959](https://github.com/pnpm/pnpm/issues/8959). - Fix infinite loop caused by lifecycle scripts using `pnpm` to execute other scripts during `pnpm install` with `verify-deps-before-run=install` [#&#8203;8954](https://github.com/pnpm/pnpm/issues/8954). - Replace `strip-ansi` with the built-in `util.stripVTControlCharacters` [#&#8203;9009](https://github.com/pnpm/pnpm/pull/9009). - Do not print patched dependencies as ignored dependencies that require a build [#&#8203;8952](https://github.com/pnpm/pnpm/issues/8952). ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://figma.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/figma.svg" width="80" alt="Figma"></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://prisma.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/prisma.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/prisma_light.svg" /> <img src="https://pnpm.io/img/users/prisma.svg" width="180" alt="Prisma" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </picture> </a> </td> </tr> <tr> <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="120" alt="Nx" /> </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> </tr> <tr> <td align="center" valign="middle"> <a href="https://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://canva.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/canva.svg" width="120" alt="Canva" /> </a> </td> </tr> </tbody> </table> ### [`v10.0.0`](https://github.com/pnpm/pnpm/releases/tag/v10.0.0): pnpm 10 [Compare Source](https://github.com/pnpm/pnpm/compare/v9.15.9...v10.0.0) ##### Major Changes - Lifecycle scripts of dependencies are not executed during installation by default! This is a breaking change aimed at increasing security. In order to allow lifecycle scripts of specific dependencies, they should be listed in the `pnpm.onlyBuiltDependencies` field of `package.json` [#&#8203;8897](https://github.com/pnpm/pnpm/pull/8897). For example: ```json { "pnpm": { "onlyBuiltDependencies": ["fsevents"] } } ``` Read [pnpm 10.0.0 Blocks Lifecycle Scripts by Default](https://socket.dev/blog/pnpm-10-0-0-blocks-lifecycle-scripts-by-default) to learn about the motivation of the change. If you want the old pre v10 behaviour, so you want to allow all dependencies to run postinstall scripts, then add this to your `package.json`: ```json { "pnpm": { "neverBuiltDependencies": [] } } ``` - `pnpm link` behavior updated: The `pnpm link` command now adds overrides to the root `package.json`. - In a workspace: The override is added to the root of the workspace, linking the dependency to all projects in the workspace. - Global linking: To link a package globally, run `pnpm link` from the package’s directory. Previously, you needed to use `pnpm link -g`. Related PR: [#&#8203;8653](https://github.com/pnpm/pnpm/pull/8653) - Secure hashing with SHA256: Various hashing algorithms have been updated to SHA256 for enhanced security and consistency: - Long paths inside `node_modules/.pnpm` are now hashed with SHA256. - Long peer dependency hashes in the lockfile now use SHA256 instead of MD5. (This affects very few users since these are only used for long keys.) - The hash stored in the `packageExtensionsChecksum` field of `pnpm-lock.yaml` is now SHA256. - The side effects cache keys now use SHA256. - The pnpmfile checksum in the lockfile now uses SHA256 ([#&#8203;8530](https://github.com/pnpm/pnpm/pull/8530)). - The patch file checksums in the lockfile now use SHA256. - Configuration updates: - `manage-package-manager-versions`: enabled by default. pnpm now manages its own version based on the `packageManager` field in `package.json` by default. - `public-hoist-pattern`: nothing is hoisted by default. Packages containing `eslint` or `prettier` in their name are no longer hoisted to the root of `node_modules`. Related Issue: [#&#8203;8378](https://github.com/pnpm/pnpm/issues/8378) - Upgraded `@yarnpkg/extensions` to v2.0.3. This may alter your lockfile. - `virtual-store-dir-max-length`: the default value on Windows has been reduced to 60 characters. - Reduced environment variables for scripts: During script execution, fewer `npm_package_*` environment variables are set. Only `name`, `version`, `bin`, `engines`, and `config` remain. Related Issue: [#&#8203;8552](https://github.com/pnpm/pnpm/issues/8552) - All dependencies are now installed even if `NODE_ENV=production`. Related Issue: [#&#8203;8827](https://github.com/pnpm/pnpm/issues/8827) - Changes to the global store: - Store version bumped to v10. - Some registries allow identical content to be published under different package names or versions. To accommodate this, index files in the store are now stored using both the content hash and package identifier. This approach ensures that we can: 1. Validate that the integrity in the lockfile corresponds to the correct package, which might not be the case after a poorly resolved Git conflict. 2. Allow the same content to be referenced by different packages or different versions of the same package. Related PR: [#&#8203;8510](https://github.com/pnpm/pnpm/pull/8510) Related Issue: [#&#8203;8204](https://github.com/pnpm/pnpm/issues/8204) - More efficient side effects indexing. The structure of index files in the store has changed. Side effects are now tracked more efficiently by listing only file differences rather than all files. Related PR: [#&#8203;8636](https://github.com/pnpm/pnpm/pull/8636) - A new `index` directory stores package content mappings. Previously, these files were in `files`. - Other breaking changes: - The `#` character is now escaped in directory names within `node_modules/.pnpm`. Related PR: [#&#8203;8557](https://github.com/pnpm/pnpm/pull/8557) - Running `pnpm add --global pnpm` or `pnpm add --global @pnpm/exe` now fails with an error message, directing you to use `pnpm self-update` instead. Related PR: [#&#8203;8728](https://github.com/pnpm/pnpm/pull/8728) - Dependencies added via a URL now record the final resolved URL in the lockfile, ensuring that any redirects are fully captured. Related Issue: [#&#8203;8833](https://github.com/pnpm/pnpm/issues/8833) - The `pnpm deploy` command now only works in workspaces that have `inject-workspace-packages=true`. This limitation is introduced to allow us to create a proper lockfile for the deployed project using the workspace lockfile. - Removed conversion from lockfile v6 to v9. If you need v6-to-v9 conversion, use pnpm CLI v9. - `pnpm test` now passes all parameters after the `test` keyword directly to the underlying script. This matches the behavior of `pnpm run test`. Previously you needed to use the `--` prefix. Related PR: [#&#8203;8619](https://github.com/pnpm/pnpm/pull/8619) - `node-gyp` updated to version 11. - `pnpm deploy` now tries creating a dedicated lockfile from a shared lockfile for deployment. It will fallback to deployment without a lockfile if there is no shared lockfile or `force-legacy-deploy` is set to `true`. ##### Minor Changes - Added support for a new type of dependencies called ["config dependencies"](https://pnpm.io/config-dependencies). These dependencies are installed before all the other types of dependencies (before "dependencies", "devDependencies", "optionalDependencies"). Config dependencies cannot have dependencies of their own or lifecycle scripts. They should be added using exact version and the integrity checksum. Example: ```json { "pnpm": { "configDependencies": { "my-configs": "1.0.0+sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==" } } } ``` Related RFC: [#&#8203;8](https://github.com/pnpm/rfcs/pull/8). Related PR: [#&#8203;8915](https://github.com/pnpm/pnpm/pull/8915). - New settings: - New `verify-deps-before-run` setting. This setting controls how `pnpm` checks `node_modules` before running scripts: - `install`: Automatically run `pnpm install` if `node_modules` is outdated. - `warn`: Print a warning if `node_modules` is outdated. - `prompt`: Prompt the user to confirm running `pnpm install` if `node_modules` is outdated. - `error`: Throw an error if `node_modules` is outdated. - `false`: Disable dependency checks. Related Issue: [#&#8203;8585](https://github.com/pnpm/pnpm/issues/8585) - New `inject-workspace-packages` setting enables hard-linking all local workspace dependencies instead of symlinking them. Previously, this could be achieved using [`dependenciesMeta[].injected`](https://pnpm.io/package_json#dependenciesmetainjected), which remains supported. Related PR: [#&#8203;8836](https://github.com/pnpm/pnpm/pull/8836) - Faster repeat installs: On repeated installs, `pnpm` performs a quick check to ensure `node_modules` is up to date. Related PR: [#&#8203;8838](https://github.com/pnpm/pnpm/pull/8838) - `pnpm add` integrates with default workspace catalog: When adding a dependency, `pnpm add` checks the default workspace catalog. If the dependency and version requirement match the catalog, `pnpm add` uses the `catalog:` protocol. Without a specified version, it matches the catalog’s version. If it doesn’t match, it falls back to standard behavior. Related Issue: [#&#8203;8640](https://github.com/pnpm/pnpm/issues/8640) - `pnpm dlx` now resolves packages to their exact versions and uses these exact versions for cache keys. This ensures `pnpm dlx` always installs the latest requested packages. Related PR: [#&#8203;8811](https://github.com/pnpm/pnpm/pull/8811) - No `node_modules` validation on certain commands. Commands that should not modify `node_modules` (e.g., `pnpm install --lockfile-only`) no longer validate or purge `node_modules`. Related PR: [#&#8203;8657](https://github.com/pnpm/pnpm/pull/8657) ##### 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> <td align="center" valign="middle"> <a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/sanity.svg" width="180" alt="Bit"></a> </td> <td align="center" valign="middle"> <a href="https://figma.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"><img src="https://pnpm.io/img/users/figma.svg" width="80" alt="Figma"></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://prisma.io/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/prisma.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/prisma_light.svg" /> <img src="https://pnpm.io/img/users/prisma.svg" width="180" alt="Prisma" /> </picture> </a> </td> </tr> <tr> <td align="center" valign="middle"> <a href="https://uscreen.de/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/uscreen.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/uscreen_light.svg" /> <img src="https://pnpm.io/img/users/uscreen.svg" width="180" alt="u|screen" /> </picture> </a> </td> <td align="center" valign="middle"> <a href="https://www.jetbrains.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/jetbrains.svg" /> <img src="https://pnpm.io/img/users/jetbrains.svg" width="180" alt="JetBrains" /> </picture> </a> </td> </tr> <tr> <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="120" alt="Nx" /> </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> </tr> <tr> <td align="center" valign="middle"> <a href="https://route4me.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/route4me.svg" width="220" alt="Route4Me" /> </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://canva.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank"> <img src="https://pnpm.io/img/users/canva.svg" width="120" alt="Canva" /> </a> </td> </tr> </tbody> </table> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMjAuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjI5LjQiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->
chore(deps): update pnpm to v11
Some checks failed
renovate/artifacts Artifact file update failure
b84ff51a43
Author
Collaborator

⚠️ Artifact update problem

Renovate failed to update an artifact related to this branch. You probably do not want to merge this PR as-is.

♻ Renovate will retry this branch, including artifacts, only when one of the following happens:

  • any of the package files in this branch needs updating, or
  • the branch becomes conflicted, or
  • you click the rebase/retry checkbox if found above, or
  • you rename this PR's title to start with "rebase!" to trigger it manually

The artifact failure details are included below:

File name: package.json
Command failed: corepack use pnpm@11.7.0

### ⚠️ Artifact update problem Renovate failed to update an artifact related to this branch. You probably do not want to merge this PR as-is. ♻ Renovate will retry this branch, including artifacts, only when one of the following happens: - any of the package files in this branch needs updating, or - the branch becomes conflicted, or - you click the rebase/retry checkbox if found above, or - you rename this PR's title to start with "rebase!" to trigger it manually The artifact failure details are included below: ##### File name: package.json ``` Command failed: corepack use pnpm@11.7.0 ```
renovate force-pushed renovate/pnpm-11.x from b84ff51a43
Some checks failed
renovate/artifacts Artifact file update failure
to 5142f41b36
Some checks failed
renovate/artifacts Artifact file update failure
2026-06-16 02:22:01 +02:00
Compare
renovate force-pushed renovate/pnpm-11.x from 5142f41b36
Some checks failed
renovate/artifacts Artifact file update failure
to c8a26f0b0e 2026-06-17 02:19:10 +02:00
Compare
renovate force-pushed renovate/pnpm-11.x from c8a26f0b0e to 39f1ea57f8 2026-06-19 02:17:56 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 39f1ea57f8 to 4da29e0220 2026-06-24 02:17:46 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 4da29e0220 to f99ce3b3aa 2026-07-05 02:16:18 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from f99ce3b3aa to 2025bb813d 2026-07-10 02:17:30 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 2025bb813d to ad28d1f253 2026-07-12 02:17:36 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from ad28d1f253 to d97ecb1a87 2026-07-14 02:17:52 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from d97ecb1a87 to 163abf3ecb 2026-07-17 02:18:21 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 163abf3ecb to ae09f8e438 2026-07-18 02:18:13 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from ae09f8e438 to 4853a2b7b7 2026-07-19 02:15:58 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 4853a2b7b7 to 34a30f5dd8 2026-07-20 02:20:23 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 34a30f5dd8 to 84cb591253 2026-07-23 02:17:39 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 84cb591253 to 65eae1690b 2026-07-24 02:15:11 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 65eae1690b to c24cb6c760 2026-07-30 02:17:24 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from c24cb6c760 to 201bb1c6d1 2026-08-04 02:17:50 +02:00 Compare
renovate force-pushed renovate/pnpm-11.x from 201bb1c6d1 to 6571962a61 2026-08-10 02:16:48 +02:00 Compare
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin renovate/pnpm-11.x:renovate/pnpm-11.x
git switch renovate/pnpm-11.x

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff renovate/pnpm-11.x
git switch renovate/pnpm-11.x
git rebase main
git switch main
git merge --ff-only renovate/pnpm-11.x
git switch renovate/pnpm-11.x
git rebase main
git switch main
git merge --no-ff renovate/pnpm-11.x
git switch main
git merge --squash renovate/pnpm-11.x
git switch main
git merge --ff-only renovate/pnpm-11.x
git switch main
git merge renovate/pnpm-11.x
git push origin main
Sign in to join this conversation.
No description provided.