PNpM CLI
This release fixes a crash on registry responses with too many content encodings (GHSA-xjj6-f33q-929c) and sizes the install worker pool by the container's CPU quota. A repeat pnpm install now acts on more setting changes.
Patch Changes
Crashes and security
-
A registry response with too many content encodings can no longer crash pnpm. pnpm now uses undici 7.30.1, which fixes GHSA-xjj6-f33q-929c.
-
pnpm installnow sizes its worker pool by the CPU quota of the container it runs in, such as a Kubernetes CPU limit, when that quota is smaller than the number of CPUs the container may run on. The defaultworkspaceConcurrencyrespects the quota the same way. On a CI runner with a 4-CPU quota and hundreds of host CPUs, pnpm started hundreds of workers and ran out of memory #17382.
Repeat installs and changed settings
-
A repeat
pnpm installnow acts on a change to these settings. Before, it reported "Already up to date".storeDirorvirtualStoreDir: it recreatesnode_modules.virtualStoreDirMaxLength: it renames the virtual store directories.dangerouslyAllowAllBuildsturned on: it runs the builds it skipped.trustLockfileturned off: it verifies the lockfile.
-
pnpm add,pnpm remove, andpnpm updatenow fail when thenode-linkersetting differs from the one recorded innode_modules. Apnpm installof the whole workspace recreatesnode_moduleswith the newnode-linker, and an install filtered to some projects fails pnpm/tasks#203. -
An install filtered to some workspace projects now fails if
node_moduleswas installed with a differentnodeLinker,hoistPattern,publicHoistPattern, store, or virtual store. Before, it recreatednode_modulesand left the projects it skipped without their dependencies. Apnpm installof the whole workspace still recreatesnode_modulespnpm/tasks#217. -
pnpm installnow takes its fast path in a workspace withpatchedDependencieswhen the previous install ran with another major version of pnpm. -
pnpm installnow relinks the bins of a workspace package when itsbinfield changes, including with--frozen-lockfileand an unchanged lockfile. A filtered install relinks them in the selected projects, and the next install that covers the remaining projects relinks them there #17324. -
pnpm installnow removes command shims fromnode_modules/.binwhen a workspace dependency renames or removes an entry from itsbinfield pnpm/tasks#211. -
With
nodeLinker: hoisted, an install that stops partway no longer leaves the next install trusting the packages it was replacing. Before, reverting the change that started the stopped install, such as a patch edit, kept the half-replaced package innode_modules. -
pnpm runandpnpm execno longer report the dependencies as out of date after a lockfile change whendedupePeersistrue#17322.
Resolving dependencies and the lockfile
-
A package that a plain range and a
<prefix>:specifier both resolve from one registry is now recorded once inpnpm-lock.yamland installed once. The lockfile key names the registry a package resolved from. When that registry declares a prefix, throughprefixinregistriesor throughnamedRegistries, the package is keyed<name>@<prefix>:<version>however its dependency was written: with the prefix, as a plain range its scope routes to that registry, or through the default registry. Before, the plain range was keyed<name>@<version>, so one tarball was installed twice andinstanceofchecks and module singletons broke between the two copies. The same name and version served by two registries still get separate entries. When several prefixes declare one registry, its packages are keyed by the lexicographically smallest prefix.If a scope you route reaches a registry that also declares a prefix, your next
pnpm installre-keys those entries, which shows up as a lockfile diff. Commit it.pnpm install --frozen-lockfileinstalls the lockfile as recorded. -
pnpm installnow resolves a scope's packages again when the scope is routed to another registry inregistries. Before, the lockfile kept the versions and integrity resolved from the old registry, so the install failed when the new registry did not serve a locked version or served different content. pnpm records in the workspace state which registry each scope routed to, so a fresh clone without that record installs the lockfile as recorded. Changing the default registry resolves nothing again, andpnpm install --frozen-lockfileis unchanged. -
An optional dependency written with a named-registry prefix, such as
work:^1.0.0, now fails the install when it cannot be resolved but the lockfile already has a matching entry from that registry. Such a dependency was skipped, which removed its entries from the lockfile. -
With
injectWorkspacePackages: true, aworkspace:dependency written as a relative path, such asworkspace:../lib-a, in a workspace package now resolves from that package's directory #17284. -
Fixed
pnpm installfailing withERR_PNPM_UNSUPPORTED_PROTOCOLwhen a workspace package injected through a relative path, such asworkspace:../lib, hascatalog:dependencies. Their catalog entries now resolve the way they do for a package injected by name #17280. -
pnpm installnow applies theserverTyperegistry setting when it updates the lockfile for an override or catalog change without a full resolution. pnpm wrote the tarball URLs of a declared registry into the lockfile in that case. -
Added the
pnprvalue to theserverTyperegistry setting. pnpm leaves the tarball URLs of a pnpr registry out ofpnpm-lock.yaml. -
A
registriesentry whoseprefixis__proto__is no longer ignored. -
Installs delegated to a pnpr server now resolve every prefix declared for a registry URL. A dependency or lockfile entry that used the second of two prefixes for the same registry, such as
zeta:next towork:innamedRegistries, failed on the server pnpm/tasks#204.
Registries, proxies, and downloading pnpm
-
The proxy settings
httpProxy,httpsProxy,noProxy,proxy, andnoproxyset in the globalconfig.yaml, throughPNPM_CONFIG_HTTPS_PROXYand the matching variables, or as--config.httpsProxyon the command line now apply topnpm self-updateand to the download of the pnpm version pinned inpackageManager. Previously, these requests read the proxy only from.npmrcand theHTTPS_PROXYfamily of variables pnpm/tasks#215. -
When
https-proxyisfalse, pnpm now downloads the pnpm version pinned bypackageManagerthrough the legacyproxysetting, as installs already do. Settingproxytofalsenow also stops that download from using theHTTP_PROXYenvironment variable. The signature check of the pinned pnpm now uses the same proxy and TLS settings as its download pnpm/tasks#193. -
strictSslandlocalAddressset in the globalconfig.yaml, throughPNPM_CONFIG_STRICT_SSLandPNPM_CONFIG_LOCAL_ADDRESS, or on the command line now apply topnpm self-updateand to the download of the pnpm version pinned inpackageManager. These requests read them from.npmrconly before.--config.localAddressnow reaches them in the camelCase spelling too pnpm/tasks#201.
Commands
-
pnpm audit --ignoreandpnpm audit --ignore-unfixablenow exit with a non-zero code when vulnerabilities at or above the audit level remain after ignoring. Before, these commands always exited with code 0. -
pnpm audit --fixandpnpm audit --interactivenow fail withERR_PNPM_AUDIT_FIX_WITH_IGNOREwhen combined with--ignoreor--ignore-unfixable. Before, the fix ran and the ignore flags had no effect. -
pnpm ci --lockfileandpnpm ci --config.lockfile=trueno longer deletepnpm-lock.yaml.pnpm cinow always keeps the lockfile and runs a frozen install from it. -
pnpm deploynow keeps a deployed symlink to a directory inside the project even if the directory is not among the deployed files, such as a link intonode_modules#17288. -
pnpm packandpnpm publishagain include the files of apublishConfig.directorythat is reached through a symlink, together with its bundled dependencies #17390. -
pnpm -r publish --batchnow sendsPUT /-/pnpr/v0/publish, the batch publish endpoint that pnpr serves. -
pnpm store prunenow keeps the packages that a project still uses when pnpm copied or cloned them intonode_modules. These include patched packages, built packages, and every package installed withpackageImportMethod: copy. Before, the prune removed them, and the next install downloaded them again #7192. -
pnpm store prunenow keeps the packages of a project that was installed with a different symlinked spelling of the store path. Previously, prune dropped such a project from its list and removed the packages only that project used from the global virtual store.
Speed and output
-
Sped up installs of projects whose local directory dependencies share transitive local directory dependencies. pnpm no longer checks a shared directory again for each direct dependency that reaches it #17374.
-
Output that fills the terminal, such as
pnpm run --streamscript output, is now written once. Before, every new line also rewrote all the lines already on screen #17387. -
The warning about unrecognized settings now marks
symlinkedLockfileTargetDirsas a setting of a newer pnpm version.
<!-- 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> <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> <td align="center" valign="middle"> <a href="https://notion.com/?utm_source=pnpm&utm_medium=release_notes" target="_blank" rel="noopener noreferrer"><img src="https://pnpm.io/img/users/notion.svg" width="80" alt="Notion"></a> </td> </tr> <tr> <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> </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://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> <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> </tr> <tr> <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> <td align="center" valign="middle"> <a href="https://latitude.so/?utm_source=pnpm&utm_medium=release_notes" target="_blank" rel="noopener noreferrer"><img src="https://pnpm.io/img/users/latitude.svg" width="160" alt="Latitude"></a> </td> </tr> </tbody> </table>
<!-- sponsors end -->