fix(deps): update frontend non-major dependencies #122

Open
Renovate wants to merge 1 commit from renovate/frontend-non-major-dependencies into main
Collaborator

This PR contains the following updates:

Package Change Age Confidence
pnpm (source) 11.9.0 → 11.28.11 age confidence
recharts 3.9.0 → 3.10.1 age confidence
typescript-eslint (source) 8.62.0 → 8.72.2 age confidence

Release Notes

pnpm/pnpm (pnpm)

v11.28.11: pnpm 11.28.11

Compare Source

pnpm 11.28.11 fixes frozen installs with excludeLinksFromLockfile, pnpm link in workspaces, pnpm deploy with dangling symlinks, and verifyDepsBeforeRun starting needless installs.

Patch Changes
Installing packages
  • pnpm deploy now keeps a symlink in the project whose target is missing from the source, such as a link into a node_modules directory that was removed after the build. Deploy used to fail with ENOENT on such a link #​17571.

  • A package with bundledDependencies and a build script now keeps its bundled dependencies when it is restored from the side-effects cache #​17523.

  • pnpm install now links the runtime that an earlier pnpm install --no-runtime skipped #​17542.

  • Commands of a package whose bin paths contain excess parent directory segments, such as ../dist/cli.js, are no longer missing. Such paths now resolve inside the package #​17586.

  • Generated POSIX shell shims now quote their paths, so shell special characters in a path stay literal.

  • A repeat pnpm install now rewrites the bin shims after extendNodePath changes. Before, it reported "Already up to date" and the shims kept the NODE_PATH of the previous setting.

Lockfile and resolution
  • pnpm install --frozen-lockfile now accepts the lockfile it wrote with excludeLinksFromLockfile and linkWorkspacePackages on, when a project depends on a workspace package through a plain version range or a catalog: entry. It used to fail with ERR_PNPM_OUTDATED_LOCKFILE.

  • pnpm install --frozen-lockfile, pnpm approve-builds, and pnpm rebuild now accept a lockfile that resolves a * dependency to a prerelease latest version. pnpm wrote such a lockfile and then reported it as outdated #​17594.

  • Packages from the default registry keep plain lockfile keys, even when a prefix such as npmjs points at the registry set as registry. A dependency written with such a prefix shares the plain entry of the same package. The next install rewrites keys that earlier versions qualified this way #​17575.

  • Relative local paths in root overrides now resolve from the workspace root when each project has its own lockfile #​17691.

    Installing a local directory dependency no longer fails when another project's install is writing a lockfile in that directory.

  • Peer deduplication no longer gives a project different copies of a dependency across direct and transitive paths when an optional peer has no provider #​17666.

  • A Node.js version range such as >=26.13, for example in devEngines.runtime, now resolves to the newest stable release that satisfies it. pnpm picks a prerelease only when no stable release matches #​17516.

verifyDepsBeforeRun
  • With verifyDepsBeforeRun, pnpm run and pnpm exec now report dependencies as out of date after a dependency is added to the package.json of a local directory dependency, such as "lib": "file:../lib". Before, the command ran without the new dependency installed.

  • verifyDepsBeforeRun no longer reports dependencies as out of sync when only the version field of a single-project repository changed #​17560. The same holds for a workspace project that no dependency can resolve to. A script run after such a change no longer starts an install first.

  • In a workspace, pnpm link <dir> now adds the link: dependency to the package.json of the project where the command runs, not to the workspace root's package.json. The link is created in that project's node_modules, as documented. The override is still written to the root pnpm-workspace.yaml.

  • pnpm link with several paths now records every linked package in the overrides of pnpm-workspace.yaml. Some of them could be missing before.

  • pnpm link now fails without changing package.json or pnpm-workspace.yaml when the linked package's name is not a valid npm package name. It used to write that name to both files, which made every later install fail #​17475.

pnpm update
  • pnpm update with only negated selectors, such as pnpm update '!foo', now leaves the dependencies listed in update.ignoreDeps unchanged pnpm/tasks#243.

  • pnpm update --depth 0 without selectors now does nothing when every direct dependency is listed in update.ignoreDeps. Before, it failed with ERR_PNPM_NO_PACKAGE_IN_DEPENDENCIES pnpm/tasks#251.

Store and self-update
  • pnpm store prune now keeps packages linked from a configured modules directory pnpm/tasks#230.

  • pnpm store status no longer reports untouched packages as modified when the global virtual store is enabled. If the installed global-store layout cannot be verified, the command reports ERR_PNPM_STORE_STATUS_UNVERIFIABLE and asks for a reinstall #​17631.

  • pnpm store add now fails right away with ERR_PNPM_FROZEN_STORE_WRITE when frozenStore is enabled. It used to retry each download for minutes before failing, or fail with a SQLite error on an empty store.

  • pnpm self-update now reinstalls a cached engine if its executable cannot run. This repairs shared store entries damaged by an earlier install #​17582.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit Cloudflare

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude Syntax

v11.28.10: pnpm 11.28.10

Compare Source

pnpm 11.28.10 stops pnpm store prune from deleting other stores when cacheDir points to their parent directory. It also fixes globally installed commands that load hoisted dependencies, and repeat installs that missed changes to local dependencies.

Patch Changes
Installing packages
  • pnpm store prune preserves other stores and global package data when cacheDir points to their parent directory.

  • Commands installed with pnpm add --global now find the dependencies that pnpm hoists for their package. A package that loads a dependency it does not declare, such as a native addon's platform-specific package, failed with "Cannot find module". Reinstall such a package with pnpm add --global to update its existing command #​17503.

  • pnpm prune --prod no longer fails with ERR_PNPM_EXDEV when node_modules was copied from an earlier Docker build stage #​17424.

  • pnpm install now retries a Node.js runtime zip download when the connection drops partway through. A download that still fails names its URL. Before, a single dropped connection ended the install with terminated #​17411.

  • With the global virtual store, a change to a dependency of one package in a dependency cycle now gives every package in that cycle a new directory. Before, the other packages kept their directories and still linked the old copy of the changed package, so the project could load two copies of it #​17466.

    Packages in a dependency cycle, and packages that depend on one, move to new global virtual store directories once after this update. Those that run a build miss the side-effects cache once.

  • pnpm install and pnpm rebuild now refresh privately hoisted .bin shims in node_modules/.pnpm/node_modules/.bin after a dependency build replaces a script target with a native executable #​17402.

  • The Node.js latest selector now chooses the newest stable release #​17490.

  • The standalone @pnpm/exe builds now embed Node.js 26.13.0.

Repeat installs and lockfiles
  • pnpm install now resolves a local directory again after its package.json changes when an override or a package extension adds it to the dependencies of a registry package. pnpm install --frozen-lockfile fails on a lockfile that still records the old dependencies of such a directory #​17486.

  • With injectWorkspacePackages and per-project lockfiles, pnpm install now updates a project's lockfile when a local tarball that an injected workspace project depends on is replaced. The project's lockfile kept the old version and integrity before.

  • pnpm install now detects a change to a local tarball or directory that only a pnpmfile readPackage hook depends on. A repeat install reported "Already up to date" and kept the old contents before pnpm/tasks#227.

  • pnpm install now relinks a workspace: or link: dependency whose link was deleted from node_modules. It used to report "Already up to date" and leave the link missing #​17485.

  • Merging git branch lockfiles now keeps a workspace project whose directory is named __proto__. It was dropped from the merged lockfile before pnpm/tasks#59.

Adding and publishing packages
  • pnpm add no longer rewrites a catalog entry set to the dist-tag that the dependency resolves through. For example, an entry beta stays beta after pnpm add foo@beta or pnpm add foo. Before, the entry was replaced with the version the tag pointed to pnpm/tasks#225.

  • pnpm pack and pnpm publish now always include the binary file declared by a string bin field in package.json, even when files or .npmignore would otherwise exclude it.

  • When the version or range given to pnpm unpublish matches every published version, the error now says so and shows the same command with --force. It suggested running pnpm unpublish <pkg>@<version>, the command that had just failed.

Running commands
  • Every command, including pnpm --version, pnpm self-update, and invocations with unknown flags, now applies the same packageManager and devEngines.packageManager settings when switching to the pinned pnpm version or recording it in pnpm-lock.yaml. --config.<key> flags and lockfileDir now reach the version switch and lockfile sync on every entry point. Unreadable settings in pnpm-workspace.yaml or the global config.yaml that do not affect the pin decision no longer block the version switch pnpm/tasks#222.

  • On Windows, the shell shim of a .cmd or .bat bin now runs it under Git Bash when MSYS argument conversion is off, such as with MSYS_NO_PATHCONV=1 or MSYS2_ARG_CONV_EXCL='*'. The shim used to start an interactive cmd.exe prompt #​17480.

  • pnx and pnpm create now run the command in the directory selected by --dir or --workspace-root. Without either flag, the command still runs in the directory pnpm was started in.

  • The error for a dependency with an invalid name in a project's manifest now names the project's directory. It used to say only "The current package", which did not tell which workspace project to fix #​17475.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit Cloudflare

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude Syntax

v11.28.9: pnpm 11.28.9

Compare Source

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 install now 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 default workspaceConcurrency respects 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 install now acts on a change to these settings. Before, it reported "Already up to date".

    • storeDir or virtualStoreDir: it recreates node_modules.
    • virtualStoreDirMaxLength: it renames the virtual store directories.
    • dangerouslyAllowAllBuilds turned on: it runs the builds it skipped.
    • trustLockfile turned off: it verifies the lockfile.
  • pnpm add, pnpm remove, and pnpm update now fail when the node-linker setting differs from the one recorded in node_modules. A pnpm install of the whole workspace recreates node_modules with the new node-linker, and an install filtered to some projects fails pnpm/tasks#203.

  • An install filtered to some workspace projects now fails if node_modules was installed with a different nodeLinker, hoistPattern, publicHoistPattern, store, or virtual store. Before, it recreated node_modules and left the projects it skipped without their dependencies. A pnpm install of the whole workspace still recreates node_modules pnpm/tasks#217.

  • pnpm install now takes its fast path in a workspace with patchedDependencies when the previous install ran with another major version of pnpm.

  • pnpm install now relinks the bins of a workspace package when its bin field changes, including with --frozen-lockfile and 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 install now removes command shims from node_modules/.bin when a workspace dependency renames or removes an entry from its bin field 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 in node_modules.

  • pnpm run and pnpm exec no longer report the dependencies as out of date after a lockfile change when dedupePeers is true #​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 in pnpm-lock.yaml and installed once. The lockfile key names the registry a package resolved from. When that registry declares a prefix, through prefix in registries or through namedRegistries, 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 and instanceof checks 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 install re-keys those entries, which shows up as a lockfile diff. Commit it. pnpm install --frozen-lockfile installs the lockfile as recorded.

  • pnpm install now resolves a scope's packages again when the scope is routed to another registry in registries. 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, and pnpm install --frozen-lockfile is 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, a workspace: dependency written as a relative path, such as workspace:../lib-a, in a workspace package now resolves from that package's directory #​17284.

  • Fixed pnpm install failing with ERR_PNPM_UNSUPPORTED_PROTOCOL when a workspace package injected through a relative path, such as workspace:../lib, has catalog: dependencies. Their catalog entries now resolve the way they do for a package injected by name #​17280.

  • pnpm install now applies the serverType registry 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 pnpr value to the serverType registry setting. pnpm leaves the tarball URLs of a pnpr registry out of pnpm-lock.yaml.

  • A registries entry whose prefix is __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 to work: in namedRegistries, failed on the server pnpm/tasks#204.

Registries, proxies, and downloading pnpm
  • The proxy settings httpProxy, httpsProxy, noProxy, proxy, and noproxy set in the global config.yaml, through PNPM_CONFIG_HTTPS_PROXY and the matching variables, or as --config.httpsProxy on the command line now apply to pnpm self-update and to the download of the pnpm version pinned in packageManager. Previously, these requests read the proxy only from .npmrc and the HTTPS_PROXY family of variables pnpm/tasks#215.

  • When https-proxy is false, pnpm now downloads the pnpm version pinned by packageManager through the legacy proxy setting, as installs already do. Setting proxy to false now also stops that download from using the HTTP_PROXY environment variable. The signature check of the pinned pnpm now uses the same proxy and TLS settings as its download pnpm/tasks#193.

  • strictSsl and localAddress set in the global config.yaml, through PNPM_CONFIG_STRICT_SSL and PNPM_CONFIG_LOCAL_ADDRESS, or on the command line now apply to pnpm self-update and to the download of the pnpm version pinned in packageManager. These requests read them from .npmrc only before. --config.localAddress now reaches them in the camelCase spelling too pnpm/tasks#201.

Commands
  • pnpm audit --ignore and pnpm audit --ignore-unfixable now 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 --fix and pnpm audit --interactive now fail with ERR_PNPM_AUDIT_FIX_WITH_IGNORE when combined with --ignore or --ignore-unfixable. Before, the fix ran and the ignore flags had no effect.

  • pnpm ci --lockfile and pnpm ci --config.lockfile=true no longer delete pnpm-lock.yaml. pnpm ci now always keeps the lockfile and runs a frozen install from it.

  • pnpm deploy now keeps a deployed symlink to a directory inside the project even if the directory is not among the deployed files, such as a link into node_modules #​17288.

  • pnpm pack and pnpm publish again include the files of a publishConfig.directory that is reached through a symlink, together with its bundled dependencies #​17390.

  • pnpm -r publish --batch now sends PUT /-/pnpr/v0/publish, the batch publish endpoint that pnpr serves.

  • pnpm store prune now keeps the packages that a project still uses when pnpm copied or cloned them into node_modules. These include patched packages, built packages, and every package installed with packageImportMethod: copy. Before, the prune removed them, and the next install downloaded them again #​7192.

  • pnpm store prune now 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 --stream script 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 symlinkedLockfileTargetDirs as a setting of a newer pnpm version.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.8: pnpm 11.28.8

Compare Source

Patch Changes
  • The standalone @pnpm/exe builds now embed Node.js 26.12.1. The previously embedded Node.js 26.0.0 still trusted the certificate authority intermediates that Node.js distrusted in October 2026, so a standalone pnpm accepted TLS certificates issued under them.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.7: pnpm 11.28.7

Compare Source

This release rejects registry metadata that names a different package than the one requested, applies trustPolicy to the pnpm version a project pins, and caps unpacked package size with maxTarballUnpackedSize. It also removes support for registry revisions, fixes verifyDepsBeforeRun after filtered installs, and finishes commands with their own exit code when a pipe reader exits early.

Patch Changes
Security
  • pnpm now fails with ERR_PNPM_REGISTRY_NAME_MISMATCH if a registry returns metadata for a package other than the one requested. Before, pnpm installed the package under the name in the metadata, so allowBuilds rules for the requested package did not apply to it.

  • pnpm now applies trustPolicy to the pnpm version a project pins in packageManager or devEngines.packageManager. A pinned version whose trust evidence was downgraded fails the command before pnpm switches to it or records it in the lockfile #​16319.

  • minimumReleaseAgeExcludePrune and trustPolicyExcludePrune now keep exclusions for resolved configuration dependencies and their transitive dependencies #​17142.

  • Added the maxTarballUnpackedSize setting. pnpm install fails with ERR_PNPM_TARBALL_TOO_LARGE when the files of one package unpack to more than this many bytes, 4 GiB by default pnpm/tasks#81.

Resolving dependencies
  • Registry revisions are no longer supported. pnpm now fails with ERR_PNPM_REGISTRY_REVISIONS_UNSUPPORTED on registry metadata that selects a revision, on a +rN version specifier, and on a lockfile entry with a revision field. pnpm update --patches is removed.

  • When pnpm install resolves a dependency again, it now reuses a version that the install already resolved for the same package, as a fresh install does. Before, it kept the version the lockfile pinned and added a second copy of the package. A locked version still stays when nothing else in the install prefers another version. To pin a transitive dependency on purpose, use overrides #​17084.

  • When another workspace project adds a different version of a package, a project's auto-installed peer on that package now moves to the version a fresh install picks. It used to stay on its locked version while any other project still accepted that version #​17058.

  • An optional peer that pnpm adds to a project now keeps the version the lockfile recorded for that project only while the dependency graph still holds it. Otherwise it follows its provider to a version the graph holds. Before, pnpm kept a higher version that only the lockfile held, which left two copies of the peer #​16443.

  • A package that lists the same dependency in dependencies and as an optional peer now gets the peer bound when a project adds a provider for it later. The lockfile now records every peer a package declares, including one its own dependency supplies #​17056.

  • pnpm install --prod no longer drops a dependency that a package declares both as an optional peer and as its own dependency, when the package resolved it as its own dependency and a dev dependency provides the same package under another alias.

  • pnpm now measures a pnpm.overrides entry written as a workspace: path, such as workspace:./packages/foo, from the directory holding pnpm-workspace.yaml. It used to be measured from each package the override rewrote. The install then linked a directory that does not exist, or failed if workspace packages were injected #​17010.

  • pnpm install now removes config dependencies that are no longer declared, including when the entire configDependencies setting is removed. Frozen installs reject a lockfile that still records removed config dependencies.

  • pnpm add now reads the package name correctly from a tarball URL under a registry URL that has a path, such as https://example.com/npm/. Before, the registry path became part of the name, so a scoped package failed with ERR_PNPM_INVALID_PACKAGE_NAME.

  • pnpm add no longer warns that a gist dependency was replaced from a different source when the new specifier names the same gist in another form, such as gist:<id> and https://gist.github.com/<user>/<id>.

  • With minimumReleaseAge set, pnpm now revalidates a package's cached full metadata with a single ETag request so an unchanged registry answers with 304, and keeps using the cached copy once the registry confirms it is current, even when the metadata does not list a publish time for every version. Previously, pnpm downloaded that metadata again whenever the cached copy was older than minimumReleaseAge. Packages listed in minimumReleaseAgeExclude also resolve from cached metadata without a registry request when the lockfile already has the version their range picks.

Linking node_modules and workspaces
  • Concurrent installs that import the same package into one project now all complete. One of them used to fail with ENOTEMPTY when its copy of the package collided with the copy another install had already placed pnpm/tasks#48.

  • pnpm install no longer fails on macOS with EISDIR when it creates store directories in a group-writable store under a umask that removes owner read, such as 0o477.

  • pnpm install now succeeds when node_modules is a symlink to an existing directory. Dependency hoisting previously rejected a symlinked node_modules as an invalid destination #​17157.

  • A filtered pnpm install --no-lockfile with hoistWorkspacePackages now hoists every workspace project into node_modules/.pnpm/node_modules. It used to hoist only the selected projects pnpm/tasks#168.

  • Filtered installs remove obsolete dependencies from the installed lockfile while preserving dependencies still needed by unselected projects.

  • With sharedWorkspaceLockfile: false, pnpm install now runs the preResolution hooks and custom resolvers and fetchers of the workspace root's pnpmfile for every project, next to the project's own. A global pnpmfile now runs once per project, and each project's lockfile records the checksum of the root pnpmfile when the project has none of its own. Before, a project's own pnpmfile replaced these root hooks, the global hooks ran twice, and edits to the root pnpmfile could go unnoticed.

  • pnpm prune now removes extraneous direct packages from node_modules when package.json and pnpm-lock.yaml are already in sync. pnpm prune also accepts --filter and --recursive to prune selected workspace projects without removing dependencies of unselected projects.

Injected workspace packages
  • pnpm install --frozen-lockfile now fails with ERR_PNPM_OUTDATED_LOCKFILE when the dependencies of an injected workspace package or local directory dependency no longer match the lockfile. This covers sharedWorkspaceLockfile: false #​17008, a dependency changed to a different tarball URL or git commit #​17129, and a change in a transitive injected or local directory dependency #​17128.

  • pnpm install --frozen-lockfile no longer fails with ERR_PNPM_OUTDATED_LOCKFILE when an injected workspace package depends on a local directory under another name, such as "renamed": "file:../b" #​17130.

  • An injected workspace dependency now becomes a link when its dependencies match the workspace package's own, also on an install that leaves the package's installed dependencies as they are. Before, such an install kept it as a copy #​17094.

  • An injected workspace package that was linked now becomes a copy when the project that depends on it starts providing one of its peers at a version the package's own workspace context lacks. The link used to stay until that dependency was updated, so the package could not find the peer the project provides #​17057.

  • An injected workspace package now keeps only the files its manifest lists after a lifecycle script or a script named in syncInjectedDepsAfterScripts rebuilds it. Before, these refreshes copied every file of the package directory into the injected copy, including files that files or .npmignore leave out. With deployAllFiles: true the copy still gets every file.

  • A script listed in syncInjectedDepsAfterScripts now keeps a package's links to its own files as links in the injected copies, the way pnpm install writes them. It no longer fails when the package links to one directory twice or links back to a directory above the link. pnpm install with deployAllFiles no longer fails on such a link back either.

  • A script listed in syncInjectedDepsAfterScripts now updates the injected copies of the package it ran in when sharedWorkspaceLockfile is false or the package publishes from publishConfig.directory. Before, those copies kept the files from the last install.

Running scripts and checking dependencies
  • When the reader of pnpm's output exits early, as in pnpm outdated | head, pnpm now finishes the command and exits with the command's own exit code pnpm/tasks#133. It used to exit with code 0 at the first write to the closed pipe. That hid the result of commands such as pnpm outdated and stopped pnpm clean before it removed anything.

  • With enableGlobalVirtualStore, a Node.js resolve hook that a script registers now sees the importer as context.parentURL after pnpm's NODE_PATH fallback fails to find a bare specifier. Hooks that resolve tsconfig paths aliases from the importer failed with ERR_MODULE_NOT_FOUND #​16979.

  • pnpm run, pnpm exec, and pnpm restart now pass the install flags they were given, such as --lockfile-dir, --modules-dir, --store-dir, --offline, and --ignore-scripts, to the pnpm install that verifyDepsBeforeRun: install starts. When that install leaves node_modules out of date, pnpm now prints a warning.

  • After pnpm install --filter, pnpm run and pnpm exec now notice a changed manifest or lockfile in a project that the filtered install left out, including the workspace root after a filtered install with pruneDirectDependencies: true pnpm/tasks#181. A filtered install also preserves the recorded ignored build scripts of unselected projects, and pnpm dedupe --check and pnpm install --dry-run no longer record outdated dependencies as installed.

  • The verifyDepsBeforeRun check now holds the workspace projects that the selected project depends on, including link: workspace dependencies. --filter=<project>... now selects link: dependencies as well. With sharedWorkspaceLockfile: false, verifyDepsBeforeRun also reports dependencies as outdated when a selected project's pnpm-lock.yaml is missing pnpm/tasks#138.

  • verifyDepsBeforeRun and repeat pnpm install runs now apply overrides before comparing a modified package.json with pnpm-lock.yaml #​17127. verifyDepsBeforeRun also checks whether each importer's resolved catalog versions match the catalog snapshot in pnpm-lock.yaml, and respects lockfileDir in single-project repositories.

  • verifyDepsBeforeRun now compares manifests, lockfiles, and patch files by content hash. It notices an edit that kept the file's modification time, as cp -p, rsync -a, or an archive extraction leave it, and a patch file that was copied or touched without changing its content no longer marks dependencies as outdated #​16988.

Deploying and other commands
  • pnpm deploy now records the peer dependencies of the workspace packages it copies into the deployed lockfile. Before, pnpm rejected that lockfile with --frozen-lockfile when a deployed workspace package declared a peer and injectWorkspacePackages was off #​17093.

  • pnpm install --frozen-lockfile and verifyDepsBeforeRun now succeed inside a directory created by pnpm deploy. pnpm deploy writes self-contained workspace and lockfile settings, prunes unused patchedDependencies, and preserves workspace-level dependency resolutions on deployed directory dependencies.

  • In workspaces with sharedWorkspaceLockfile: false, pnpm patch, pnpm patch-commit, and pnpm patch-remove now resolve patch files and patchedDependencies entries at the workspace root. pnpm install checks configured patches across all workspace projects before reporting unused patches.

  • Trusted publishing with OIDC now works with registries whose URL has a path, such as https://registry.example/npm/private/. pnpm previously sent the token exchange request to the root of the registry host.

  • pnpm owner ls now lists the owners of a package on the npm registry. It reported every package as not found.

  • pnpm sbom now reads project lockfiles in workspaces with sharedWorkspaceLockfile: false, including filtered and split output, and reports the repository of a package whose repository field is a gist: shorthand.

  • pnpm licenses list reports no licenses for workspace projects not recorded in the lockfile. It errors when pnpm-lock.yaml is missing. Empty results now use the requested text or JSON format pnpm/tasks#174.

  • pnpm why now reads each selected workspace project's lockfile and modules directory when sharedWorkspaceLockfile is false pnpm/tasks#169.

  • pnpm pkg fix now converts a repository string such as github:pnpm/example to the object form, as npm pkg fix does. It also normalizes a GitHub, GitLab, or Bitbucket repository URL the way npm pkg fix does #​16980.

Configuration and setting up pnpm
  • pnpm now recognizes externalDependencies and autoInstallPeersFromHighestMatch in pnpm-workspace.yaml without warning and forwards both settings to pnpm install. Previously, setting externalDependencies in pnpm-workspace.yaml with nodeLinker: hoisted crashed pnpm install with externalDependencies.has is not a function pnpm/tasks#166.

  • pnpm now ignores a PNPM_CONFIG_* environment variable for a URL setting, such as PNPM_CONFIG_REGISTRY, when its value is not a URL. Such a value used to make every command fail with Invalid URL.

  • The warning about unrecognized settings in pnpm-workspace.yaml and the global config.yaml now names addMissingPeerTypes, autoDedupe, bootConfig, macosBackup, nodePackageMap, permissions, pipelineBase, publishWaitTimeout, python, remoteCache, saveTypes, skills, storeIndexFormat, and tools as pnpm v12 settings pnpm/tasks#167.

  • When a config file has a setting pnpm cannot read, pnpm --version now prints the version, and pmOnFail and lockfileDir in pnpm-workspace.yaml stay in force. Previously, pnpm switched to the pinned version despite pmOnFail: ignore. pnpm also no longer writes the pinned version to pnpm-lock.yaml when it cannot read every setting and the running pnpm already matches the pin.

  • pnpm now records the pinned pnpm version in the pnpm-lock.yaml under the lockfileDir set in pnpm-workspace.yaml, and resolves a relative lockfileDir from the workspace root. pnpm used to write a second pnpm-lock.yaml at the workspace root.

  • pnpm self-update now updates the project's pnpm pin when Homebrew installed pnpm or Corepack runs it. The global pnpm is left alone #​17001.

  • pnpm setup now completes when Windows registry environment values cannot be read or written. It prints PowerShell commands to configure PNPM_HOME and PATH without registry access #​17167.

  • pnpm setup now succeeds when it cannot tell which shell configuration file to update, for example in a container where SHELL is not set. It installs pnpm and prints the PNPM_HOME and PATH lines to add yourself. Previously it failed with ERR_PNPM_UNKNOWN_SHELL, and so did the installer script at get.pnpm.io #​16973.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.6: pnpm 11.28.6

Compare Source

This release stops pnpm publish from sending a CI identity token to a registry it was not issued for. It also fixes installs that dropped a dependency also declared as an optional peer, and accepts empty httpProxy and httpsProxy settings again.

Patch Changes
Security
  • pnpm publish now uses an NPM_ID_TOKEN only if its aud claim matches the selected registry, such as npm:registry.npmjs.org. A token for another registry is skipped with a warning, and pnpm falls back to the configured credentials.

  • The warning about renamed package files with invalid names no longer prints control characters from those file names.

Configuration
  • pnpm again accepts httpProxy and httpsProxy set to null or written with no value in pnpm-workspace.yaml and the global config file, and treats them as unset. Since 11.28.5 these values failed with ERR_PNPM_INVALID_SETTING.

  • pnpm now switches to the pnpm version a project pins even when it cannot read its configuration. Previously, a setting it rejected in the global config file, an .npmrc file, _auth, or pnpm-workspace.yaml stopped every command, pnpm --version included.

  • A key under a registry URL in the _auth setting that does not start with @ is now skipped with a warning, so a field a later pnpm version adds there no longer breaks this one. A key that holds an authToken object but lacks its @, such as org for @org, is still an error.

Resolving dependencies
  • pnpm no longer drops a dependency that a package also declares as an optional peer dependency, for example ajv of ajv-formats. Since 11.28.0, in some dependency graphs the package got the dependency neither as a dependency nor as a peer, and failed to import it #​16901.

  • pnpm install no longer fails with ERR_PNPM_NO_MATCHING_VERSION after a change to overrides when the lockfile resolves an optional peer dependency to an npm alias of another package #​16654.

  • pnpm install and pnpm dedupe now link an optional peer to the workspace package that the workspace root depends on when the picked version matches it. Previously they installed the registry package with the same name and version #​16706.

  • Removal overrides such as "debug>supports-color": "-" now also apply to an optional peer that a package declares only in peerDependenciesMeta #​16681.

  • pnpm dedupe now preserves a hoisted workspace package when another package uses a separately installed peer with the same name #​16935.

  • pnpm install and pnpm add --config now apply minimumReleaseAge when they resolve a config dependency. A config dependency range resolves to the newest version that is old enough, so a later clean pnpm install --frozen-lockfile accepts the lockfile #​16660.

  • pnpm install --fix-lockfile no longer removes the deprecated and hasBin fields from lockfile entries #​6600.

Workspaces and catalogs
  • A filtered install, such as pnpm install --filter <pkg>, now keeps the pnpm-lock.yaml entries of workspace projects that are missing from disk, as in a sparse checkout. Their importers, packages, and catalog entries stay even when the filter matches every project on disk #​16931.

  • catalogPrune no longer removes catalog entries that pnpm-lock.yaml still records for workspace projects missing from disk. This affected pnpm remove and installs that leave the lockfile unchanged, such as frozen installs. Before, a following frozen install failed with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH #​16679.

  • Sped up workspace discovery with subtree exclusions such as !generated/**.

Linking node_modules
  • pnpm install no longer fails on Windows with EPERM on rmdir node_modules/@scope when several workspace packages under one scope are hoisted, for example with nodeLinker: hoisted #​16690.

  • pnpm install hardlinks files from a group-writable or world-writable store again. Before this fix, pnpm copied every file from such a store into node_modules #​16677.

  • With enableGlobalVirtualStore, an install that updates node_modules now restores the dependency links of a package in the global virtual store that an interrupted install left without them. Before, such an install kept the incomplete package if the project's node_modules already recorded it #​16642.

  • Removing a link: dependency now also removes its symlink from node_modules when nodeLinker is hoisted #​16884.

  • An install that adds nothing to the store no longer changes the modification time of the store directory. CI caches that check modification times, such as GitLab's, no longer re-upload an unchanged store #​16929.

Injected workspace packages
  • With sharedWorkspaceLockfile: false, an injected workspace package installed in the same run as its dependent now holds only the files its files field selects. The copy used to also hold other files of the project, such as tsconfig.json #​16683.

  • A script listed in syncInjectedDepsAfterScripts no longer fails when it rewrites package.json while pnpm is copying its edits into the injected copies. The sync after the script now replaces a half-copied manifest.

  • Sped up frozen installs of unchanged injected workspace packages that use hardlinks.

Deploying
  • pnpm deploy without injectWorkspacePackages now binds a peer dependency of a linked workspace package to the version its parent provides, as an injected install does. Previously the deploy failed with ERR_PNPM_DEPLOY_AMBIGUOUS_PEER whenever other packages in the deployed graph depended on different versions of that peer #​16807.

  • pnpm deploy in a workspace with injectWorkspacePackages no longer crashes when a linked workspace package declares a peer dependency named after an Object.prototype member, such as constructor.

Setting up pnpm
  • pnpm now relinks the bins of a pnpm version it installed earlier for packageManager or pnpm with. A pnpm 12 version installed by a pnpm release older than 11.28.4 could keep a launcher that ran node on the native binary, so every command failed with SyntaxError: Invalid or unexpected token #​16646.

  • pnpm setup no longer tries to install pnpm globally from npm's bin directory when pnpm was installed with npm. It printed Failed to create bin at <PNPM_HOME>/bin/pnpm #​16855.

Output
  • Escape codes in script output that moved the cursor or cleared the screen garbled pnpm's output. pnpm now drops them and keeps only color codes. Color codes are dropped too when pnpm's own output is not in color.

  • When the registry rejects pnpm stage publish, the error message now starts with "Failed to stage package".

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.5: pnpm 11.28.5

Compare Source

This release reads cached registry metadata faster and makes pnpm config get --global ignore project settings. It also carries several security fixes for package archives, git dependencies, and config dependencies.

Patch Changes
Security
  • pnpm now verifies locked config dependencies against their registry before installing them. Config dependencies must come from an npm registry. The lockfile can no longer replace the integrity of a config dependency pinned with version+integrity.

  • Lockfile verification now checks the tarballs inside a variations resolution against the registry. A name@version lockfile entry with an empty variations resolution is now rejected.

  • pnpm audit signatures now verifies signatures against the integrity recorded in the lockfile. Packages without a recorded integrity cannot pass signature verification.

  • pnpm now rejects a git dependency whose lockfile repository is empty, begins with -, or contains a null byte. Git can no longer read such a value as a command-line option pnpm/tasks#84.

  • A git dependency with a #path: subpath can no longer reach files outside the repository through a symlink in the subpath.

  • pnpm pack, pnpm publish, and installs of git and local directory dependencies now leave out files that a directory symlink or a bundleDependencies entry points to outside the package directory pnpm/tasks#83 pnpm/tasks#93.

  • pnpm deploy with deployAllFiles now rejects symlinks that point outside the package directory. Local package installs with this setting apply the same check.

  • pnpm no longer hangs on a package archive with a negative PAX record length or an entry of 4 GiB or more pnpm/tasks#78 pnpm/tasks#79.

  • Large package downloads and large files inside gzip and bzip2 package archives now use bounded memory during installation. Package manifests and archive metadata larger than 64 MiB are rejected. pnpm publish also rejects manifests and README files larger than 64 MiB in pre-built tarballs before reading them into memory.

  • Two URL or local path dependencies no longer share a virtual store directory when one URL has +, #, :, or ? where the other has /. Such dependencies, including git dependencies pinned with #, now get a hash suffix on their directory name.

  • pnpm licenses now removes terminal control characters from package metadata in table output.

  • The warnings about ignored project .npmrc registry and auth settings no longer print the username and password of a URL-scoped key such as //user:password@registry.example.com/:_authToken.

Installing and resolving dependencies
  • Dependency resolution reads cached registry metadata faster. The metadata cache moved to <cache-dir>/v12/, so the first install after upgrading downloads registry metadata again. A damaged cache entry is downloaded again, or reported as an error when --offline is set #​13512.

  • pnpm install now fails with ERR_PNPM_UNSUPPORTED_PROTOCOL when a dependency uses a specifier with a protocol pnpm does not support, such as Yarn's patch:. pnpm linked such a dependency to a directory that does not exist #​16590.

  • When a dependency moves an exact dependency of its own to an older version, a peer dependency that pnpm installed automatically now moves with it. Before, pnpm install and pnpm dedupe kept the newer locked version of the peer, so the lockfile held two copies of it, for example two copies of vue pnpm/tasks#61.

  • pnpm add and pnpm install now keep the peer dependencies that pnpm-lock.yaml records for a package they did not update. A registry whose metadata disagrees with the package's package.json, for example by omitting peerDependenciesMeta, made pnpm add and pnpm dedupe write different lockfiles, so pnpm dedupe --check failed after pnpm add #​16615.

Configuration
  • pnpm config get and pnpm config list with --global or --location=global now show only the global configuration. Both flags included the project's .npmrc before. --location=global also included the project's pnpm-workspace.yaml. pnpm config get --global failed when the global bin directory was not in PATH #​16598.

  • pnpm now prints config warnings, such as an unset environment variable in .npmrc, when loading the config fails.

  • pnpm now fails when httpProxy or httpsProxy in pnpm-workspace.yaml or the global configuration is not a string.

  • pnpm dlx now uses the release entry of nodeDownloadMirrors from the workspace configuration when downloading Node.js runtimes #​11281. Mirrors for other channels, such as rc and nightly, still apply only from the global configuration.

Commands
  • pnpm run and pnpm exec now forward --config.* command-line flags to the install started by verifyDepsBeforeRun pnpm/tasks#60.

  • pnpm dlx with --package but no command now fails with 'pnpm dlx' requires a command to run. Before, it installed the package and then crashed trying to run an empty command.

  • pnpm unpublish <pkg>@<version> now deletes the tarball under the registry's path when the registry is served under one, such as Gitea's npm registry. It used to send the delete to the host root and report success without removing the version #​16568. It also no longer mistakes a sibling path such as /npm-mirror/ for the registry path /npm/ pnpm/tasks#94.

  • The interactive pnpm audit --fix picker now shows each patched version with the saveExact and savePrefix style that the override is written with #​13209.

  • pnpm list now reports the correct package paths when nodeLinker is hoisted #​9593.

  • pnpm setup now puts $PNPM_HOME/bin first on PATH in login shells that inherited it further down, such as the VS Code terminal on macOS. Before, another node took precedence over the one installed by pnpm runtime set node -g. Run pnpm setup again to update the block in your shell config #​16635.

  • pnpm setup now names the shell config file even if it is already up to date #​16608.

Output and messages
  • A warning about a project's devEngines or packageManager pin is now printed to stderr. A command such as pnpm cache path or pnpm list --json keeps only its own output on stdout #​16584.

  • The warning for a non-root resolutions field now points at the overrides field in pnpm-workspace.yaml #​11757.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.4: pnpm 11.28.4

Compare Source

pnpm 11.28.4 fixes two ways credentials could leak, makes pnpm install --frozen-lockfile accept several lockfiles it rejected, warns when an optional dependency cannot be fetched, and stops pnpm self-update from installing a second pnpm next to a Homebrew one.

Patch Changes
  • pnpm login no longer forwards credentials in its request body to another origin during redirects.

  • The error for a tarball that fails its integrity check no longer prints credentials, query strings, or fragments from the tarball URL.

Installing packages
  • pnpm install --frozen-lockfile now succeeds in a project with no dependencies when pnpm-lock.yaml records only the pinned pnpm version. Other commands write such a lockfile when they run before the first install. A lockfile missing the --- line after that section is accepted too #​16477.

  • pnpm install --frozen-lockfile again succeeds when a workspace project recorded in pnpm-lock.yaml has no directory, such as a project left out of a Docker build context. It still fails if the project's directory exists without a package.json #​16453.

  • pnpm install --frozen-lockfile no longer fails with ERR_PNPM_OUTDATED_LOCKFILE for a workspace project that declares dependenciesMeta and whose dependencies are all workspace links. pnpm now records that project's dependenciesMeta in pnpm-lock.yaml #​16457.

  • Fixed frozen installs replacing a hoisted dependency with a workspace package of the same name. A later pnpm dedupe then removed the hoisted link #​16485.

  • With enableGlobalVirtualStore on, scripts can run entry points that a CommonJS require hook loads again, such as ts-node index.ts. They failed with ERR_UNKNOWN_FILE_EXTENSION on Node.js versions without built-in TypeScript support #​16436.

Optional dependencies
  • pnpm install now prints a warning with the error when an optional dependency cannot be fetched and is skipped. The skipped package is no longer linked into node_modules as a broken symlink or listed among the added dependencies. The pnpm:skipped-optional-dependency log reports the skip with the fetch_failure reason #​16514.

  • When an optional dependency fails to build, pnpm now removes its link from node_modules. A repeat pnpm install then reports "Already up to date" and no longer reruns the failing build #​16468.

  • Fixed frozen installs creating symlinks to the working directory for skipped optional dependencies and unresolved peer dependencies #​16454.

Hoisted node_modules
  • With nodeLinker: hoisted, a filtered install now keeps the packages of the workspace projects an earlier install put in node_modules. This also covers the install that pnpm --filter <selector> run and pnpm --filter <selector> exec start before the command. Before, these installs removed every package that only the unselected projects needed #​16483.

    A filtered install of a workspace project also no longer fails with ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY after a filtered install of another project.

  • pnpm install with nodeLinker: hoisted now refreshes directories supplied by custom fetchers when reinstalling.

Speed and network
  • pnpm now revalidates cached registry metadata with a conditional request, so the registry can answer 304 Not Modified. Before, pnpm downloaded the whole document again for registries whose responses forbid caching, such as Cache-Control: no-store #​16528, and for packages published within minimumReleaseAge #​16506.

  • A fetch timeout while other downloads from the same host are still running now lowers concurrency for that host to one connection. Retries of that request, and later downloads from that host, use the lower concurrency. Other hosts keep the configured concurrency #​12791.

Running scripts
  • Scripts run without a terminal no longer start a second sh each. One watchdog per pnpm command now ends every script's process group if pnpm is killed, so pnpm -r run across many projects starts half as many processes #​16489.

  • pnpm run and pnpm exec now warn and run the command when the install that verifyDepsBeforeRun starts fails. This lets scripts run in sandboxes where pnpm cannot install, such as containers with a read-only store or no network #​15173.

  • A filtered pnpm run or pnpm exec now finds dependencies out of date when a workspace dependency of a selected project has no node_modules directory, as after a filtered install. With verifyDepsBeforeRun: install, pnpm installs that dependency before running the command pnpm/tasks#45.

  • pnpm rebuild and pnpm approve-builds refresh command launchers when a build changes a command's interpreter or replaces it with a native executable. Dependent packages' build scripts use the refreshed launchers.

Updating pnpm
  • pnpm self-update now fails for Homebrew-installed pnpm and prints the brew upgrade command for the installed formula, such as brew upgrade pnpm or brew upgrade pnpm@11. It used to install a second copy of pnpm that the Homebrew one kept shadowing #​16547.

  • On Windows, pnpm self-update now replaces a pnpm.exe left in PNPM_HOME or in PNPM_HOME\bin. In PNPM_HOME, that executable kept running the old version after a successful update. In PNPM_HOME\bin, the update failed with EPERM. If the executable was in PNPM_HOME, self-update now asks you to run pnpm setup #​9094.

  • pnpm can now switch to a packageManager version below 11 on x64 musl Linux, such as Alpine #​16467.

  • A devEngines.packageManager range now records the running pnpm in pnpm-lock.yaml only if it meets minimumReleaseAge. Otherwise pnpm records the newest version in the range that meets it. If no version in the range does, pnpm still records the running pnpm #​16431.

Filtering, settings, and other commands
  • The [<since>] filter selector works again with Git 2.24 through 2.27 #​16561. With Git older than 2.24, the selector now fails with an error that names the required Git version.

  • Package-name filters now support ? to match one character #​2817.

  • pnpm -r pkg get now reports every selected project when several share a package name. Projects with the same name are keyed by their directory relative to the workspace root. Before, only one of them appeared in the output.

  • pnpm now reports an INVALID_SETTING error when allowUnusedPatches in pnpm-workspace.yaml is not a boolean, or when ignoredOptionalDependencies or requiredScripts is not an array of strings. A quoted allowUnusedPatches value such as "false" was treated as true.

  • pnpm store path, pnpm store status, and other commands that look up the default store no longer fail when the current directory is not writable. pnpm now uses the store in the pnpm home directory in that case #​16554.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.3: pnpm 11.28.3

Compare Source

pnpm 11.28.3 updates undici to clear a security advisory, fixes "database disk image is malformed" errors when several pnpm processes share a store, and makes packages, catalogs, projects, and commands named like constructor work.

Patch Changes
Installing packages
  • pnpm now ships undici 7.29.1, so security scans of pnpm no longer report GHSA-3wwx-pv8p-q78v.

  • pnpm no longer fails with "database disk image is malformed" or reads stale store entries while another pnpm process writes to the same store.

  • Names that match built-in JavaScript object properties, such as constructor, toString, or __proto__, now work like any other name. pnpm crashed, wrote a wrong lockfile, or silently skipped such names in:

    • pnpm add, pnpm install, and pnpm import, for dependencies, peer dependencies, and file: dependencies that point to a directory named constructor.
    • Catalog entries and catalog names. Pruning unused entries crashed, and a new catalog named toString was not written.
    • Workspace projects, project directories, and files inside injected packages.
    • Registry prefixes and override version references such as $toString.
    • Hoisting, pnpm list, and pnpm why.
    • Command names. pnpm constructor runs the constructor script like any other unknown command, and pnpm help constructor no longer crashes.
    • Resolving through a pnpr server when a project lives in a directory named constructor.
  • pnpm install no longer re-resolves an up-to-date lockfile on every run when a patched package is a peer in a peer cycle #​16418.

  • POSIX bin shims and the pnpm, pn, pnpx, and pnx launchers now run inside a Nix build, where the system default path holds none of the utilities they call. Installing again replaces the shims already in node_modules #​16377.

  • In a project that pins another pnpm version, pnpm now passes a command with an option it does not know to the pinned version. Before, pnpm install --auto-dedupe failed with "Unknown option" even though the pinned pnpm supports it #​16353.

  • pnpm now fails with ERR_PNPM_INVALID_ALLOW_BUILDS when allowBuilds is not an object or one of its values is not true, false, or a string. Such values used to be ignored silently.

  • Removing a dependency whose bins are declared through directories.bin no longer leaves broken shims in node_modules/.bin.

  • A custom resolver's shouldRefreshResolution hook that rejects no longer crashes pnpm with an unhandled rejection when another hook has already asked for a refresh.

Updating dependencies
  • When minimumReleaseAge hides the version that latest points to, pnpm now falls back to a prerelease of the same major before a stable version of an older major. A stable version of the same major is still preferred. For example, while a new 1.0.0 is too new, pnpm picks 1.0.0-beta.4 rather than an old 0.0.1 #​16388.

  • pnpm --filter <project> update <pkg> now fails with ERR_PNPM_NO_PACKAGE_IN_DEPENDENCIES when the selected projects do not depend on <pkg>, also in a workspace with a shared lockfile and a root project. It used to exit successfully.

  • pnpm audit --fix now updates vulnerable packages in a single project that sets updateConfig.ignoreDependencies. It used to leave them on the vulnerable version.

  • pnpm update --global now removes hard-linked executables from PNPM_HOME when migrating packages from the old global layout #​16420.

  • Updating a pinned GitHub Action now rewrites the version in its # vX.Y.Z comment even when the action name contains the same version text. The action name used to change while the comment kept the old version.

Workspaces and deploy
  • pnpm deploy no longer fails with ERR_PNPM_DEPLOY_AMBIGUOUS_PEER in a workspace with injectWorkspacePackages: true when a workspace package also lists its peer dependency as a dev dependency #​16375.

  • pnpm deploy no longer copies the workspace root's packageManager and devEngines.packageManager fields into the deployed package.json #​16403.

  • --filter fixes:

    • A ...pkg... selector combined with another dependents selector, such as --filter ...a --filter ...b..., no longer adds the dependencies of the other selector's dependents.
    • --filter "[<since>]" now detects changes in projects whose directory names contain non-ASCII characters. The change used to be credited to the parent project.
Running scripts
  • After relaying a signal to a script, pnpm keeps waiting for a process in the script's process group whose main thread has exited while its other threads still run. Linux reports such a process as a zombie, so the wait used to end before those threads finished pnpm/tasks#56.

  • A lifecycle script run with unsafePerm: false now fails with an error when pnpm cannot create node_modules/.tmp. It used to hang.

  • pnpm run with verifyDepsBeforeRun no longer crashes with an unhandled rejection when a lockfile it did not need to compare fails to load.

  • pnpm run -r now closes the collapsible CI log section of a project whose script fails, so the output of later projects is no longer nested inside it.

  • pnpm run --resume-from no longer crashes when a saved run state file contains null.

Store
  • pnpm store prune now removes the packages that only expired pnpm dlx cache entries used, as long as the store still has another registered project. They used to stay until the next pnpm store prune #​16383.

  • pnpm store prune now stops with an error when it cannot read a project directory for a reason other than the directory missing, such as a permission error. It used to skip the directory.

Publishing and registry output
  • pnpm publish now includes bare README files and README files with Markdown extensions such as readme.markdown in registry metadata #​12704.

  • pnpm pack-app now accepts an entry file or output directory inside the project whose name starts with two dots, such as ..build/entry.cjs. It used to fail with ERR_PNPM_PACK_APP_ENTRY_OUTSIDE_PROJECT.

  • Registry error messages now always say "(response body truncated)" when pnpm cut the response body short. The marker was missing when the body was cut at exactly 64 KiB.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.2: pnpm 11.28.2

Compare Source

pnpm 11.28.2 fixes pnpm install skipping every workspace project whose common ancestor is the filesystem root, and stops pnpm run from reinstalling or installing when nothing needs it.

Patch Changes
  • pnpm install reported success without installing anything when the workspace projects' common ancestor was the filesystem root, such as / or a drive root like C:\. It now installs these projects #​16328.

  • verifyDepsBeforeRun no longer reports dependencies as outdated after a filtered install just because pnpm-lock.yaml has a newer modification time. It checks the lockfile against the packages that install put in place. Before, pnpm run reinstalled the whole workspace with lifecycle scripts on, for example after a Docker COPY brought in a lockfile with a newer mtime #​16322.

    After a filtered install, verifyDepsBeforeRun now also checks that the install put the selected projects' dependencies in place. A node_modules directory alone no longer counts as proof.

  • pnpm run and pnpm exec no longer install a project that has never been installed and has nothing to install. Such a project declares no dependencies, no peer dependencies that autoInstallPeers would fetch, and no install lifecycle scripts. The command now runs without writing node_modules or pnpm-lock.yaml #​16313.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.1: pnpm 11.28.1

Compare Source

pnpm 11.28.1 makes pnpm install work in StackBlitz WebContainers, repairs lockfiles whose patch hashes disagree with patchedDependencies, and fixes many bugs in Windows command shims, injected workspace dependencies, and pnpm deploy.

Patch Changes
Installing packages
  • pnpm install now works in StackBlitz WebContainers. On projects without a lockfile, it used to fail with ENOENT ... pnpm-lock.yaml, because pnpm did not recognize the errors that WebContainers return from asynchronous file system calls. It also failed with "this.db.exec is not a function", because node:sqlite there lacks DatabaseSync.exec. When node:sqlite cannot prepare statements either, pnpm stores the index in index.fallback #​15649.

  • pnpm install now completes after downloading a Node.js runtime specified by devEngines.runtime when pnpm runs on Node.js 24.4.x #​14667.

  • pnpm install no longer fails when a package from the registry declares a file: dependency on a directory inside itself, such as "@types/css-tree": "file:./typings/css-tree". pnpm links that dependency to the directory inside the package, as npm and Yarn do. The lockfile records it as link:<root>/typings/css-tree #​9141.

  • Installing a git-hosted dependency that has to be built no longer fails when that dependency's own dependencies have build scripts nobody approved. pnpm skips those builds while preparing the dependency, as it does without strictDepBuilds #​9764.

  • pnpm now uses pnpm to prepare a git-hosted dependency that is a pnpm workspace without a committed lockfile. It used npm before, which could skip the dependency's build #​14011.

  • When installing a git dependency over SSH fails with Permission denied (publickey), pnpm suggests checking the loaded keys with ssh-add -l. Resolving an SSH URL that refuses the key also shows a local HTTPS rewrite that leaves the recorded URL alone #​13743.

  • pnpm install --dev and pnpm fetch --dev now install the optional dependencies of devDependencies, such as the platform binaries of Biome and oxlint. The project's own optionalDependencies are still skipped #​9678.

  • pnpm install --frozen-lockfile now works on a detached HEAD when gitBranchLockfile is enabled. The install now reads the lockfiles of the local and remote-tracking branches that contain the checked-out commit. It still writes the shared pnpm-lock.yaml #​7672.

  • pnpm install on CI now fails on an outdated lockfile when preferFrozenLockfile is explicitly set to true. Setting it to true used to let CI update the lockfile #​9072.

  • pnpm install now fails with ERR_PNPM_IGNORED_BUILDS on a repeat install when strictDepBuilds is on and a dependency's build is still undecided. A repeat install against an existing node_modules reported success where a fresh install failed #​10450.

  • pnpm install now removes an optional dependency from node_modules if its install script fails. Code that checks whether the package is installed no longer finds a package that cannot load #​8756.

  • pnpm install --offline and pnpm add --offline now resolve a version range to the newest matching version whose tarball is already in the store. They used to pick the newest version in the cached metadata and fail with ERR_PNPM_NO_OFFLINE_TARBALL when its tarball was missing #​10715.

  • If an offline install fails because the registry metadata cache uses the layout from before pnpm 11.27 and 12.4, the error now names the older mirror on disk and explains that one online install repopulates the cache #​15656.

  • pnpm install now fails right away when writing package files fails because the store is full. It no longer retries the tarball download first #​8581.

  • With nodeLinker: hoisted, pnpm install now restores a workspace project's node_modules after it was deleted. Before, the install printed "Already up to date" and left the project without the dependencies nested under it.

  • Under nodeLinker: hoisted, pnpm install now clears orphaned package directories that an interrupted or failed install leaves in a project's node_modules. A directory recorded by the previous install is removed, while an unrecorded directory is moved to node_modules/.ignored. A copy already in .ignored is never overwritten #​13676.

  • Packages in an external virtualStoreDir can resolve the project's direct dependencies selected by hoistPattern. Run pnpm install --force to repair an existing installation #​5652.

  • A repeat install now keeps the fast path when a declared local file dependency is replaced by an override #​12892.

Store, build cache, and global virtual store
  • Files imported from the store now follow the umask of the install that writes them. Installing with a umask of 077 no longer leaves imported files readable by the group and others #​3807.

  • With the global virtual store, pnpm rebuild no longer modifies packages shared with projects that have not approved their build scripts #​12302.

  • The side-effects cache now restores the symlinks that a build script creates inside a package. A warm install used to replace each of them with a copy of its target #​12859.

    After upgrading, every package with a build script is built once more.

  • pnpm install now restores cached build artifacts when reinstalling a workspace that uses separate lockfiles #​12942.

  • The global virtual store and the side-effects cache now key built packages by the Node.js version that the root project's devEngines.runtime or engines.runtime pins. That is the Node.js their build scripts run with. A dependency that declares its own engines.runtime no longer changes the key for every other package.

  • Concurrent installs that share a global virtual store now run a package's build in its shared slot one at a time. A failed build leaves the slot in place and marks it for the next install to rebuild #​15568.

  • Concurrent installs no longer fail when they replace the same stale hoisted dependency link. Virtual store cleanup now keeps the temporary lockfiles that concurrent installs are still writing.

  • pnpm install keeps the owner, group, and mode of files already in a shared store, including index.db. New store files and directories inherit the store directory's group-write bit. When that directory is setgid, new files inherit its group. pnpm does not change a file's owner or group #​12765.

  • When pnpm install repairs a store file that was modified through a hard link in node_modules, the repair now keeps the file's inode on Linux and macOS. Hard-linked copies in other projects are healed at the same time. Before, only the project running the install received the restored content. On Windows the repair still replaces the file, so other projects are healed on their next install #​3445.

  • A tarball whose integrity pnpm computed during download is now found in the store on the next install. Before, that install downloaded the tarball again once the lockfile recorded the integrity #​12562.

  • pnpm now warns when it cannot hard link packages from an existing store in the pnpm home directory and uses a store on the project's filesystem. This can happen when the project is on another filesystem, such as a bind-mounted workspace in a container. The warning names both stores and suggests setting storeDir #​14505.

Resolving and linking dependencies
  • A peer dependency no longer resolves to two different versions for one package. This happened when the package peer-depends on another package and on one of that package's peers, and it is installed deeper than a direct dependency of the package that provides them #​12098.

  • An optional peer dependency is no longer resolved from another workspace project's package when the project provides one of that package's own peers at a version it rejects. This avoids bogus unmet peer errors #​13989.

  • pnpm no longer reports unmet peer dependency warnings for aliased npm: peer ranges that a tarball dependency satisfies #​11126.

  • pnpm install now links the executables of auto-installed peer dependencies into the workspace root's node_modules/.bin, including after a frozen-lockfile reinstall #​8511.

  • With resolutionMode: time-based and minimumReleaseAge both set, pnpm install no longer reports a subdependency as too new when only the time-based cutoff excludes it. Such subdependencies used to fail a strict install with ERR_PNPM_NO_MATURE_MATCHING_VERSION, or were added to minimumReleaseAgeExclude #​13569.

    A transitive dependency that has no matching version published before the time-based cutoff now resolves to the lowest matching version allowed by minimumReleaseAge. pnpm picks a version younger than minimumReleaseAge only if no older version matches #​16298.

  • With minimumReleaseAge set, re-resolving the lockfile no longer rewrites the peerDependencies recorded for a package whose version did not change. This happened when the registry metadata of a package differed from the package.json in its tarball #​13988.

  • pnpm no longer revalidates cached registry metadata when the registry sends Cache-Control: max-age=0, no-cache, or no-store. It downloads the metadata again, so a version newly published to such a registry is visible on the next install #​13487.

  • pnpm's built-in package compatibility database no longer applies to a project's own manifest. A project named like a published package, such as vue-loader, no longer gains dependencies on pnpm install or pnpm update. User-configured packageExtensions still apply to project manifests #​11700.

  • Relative local tarball paths in pnpm.overrides without an explicit file: prefix are now rebased correctly for workspace packages #​11131.

  • pnpm no longer reports pnpm-lock.yaml as broken when a project depends on a package named constructor. A __proto__ key in the lockfile is now kept as a plain entry when pnpm reads or writes the lockfile. It no longer replaces the prototype of the objects pnpm builds from it #​11028.

  • With nodeLinker: pnp, a workspace package can now require another workspace package it depends on #​3567. On Windows, workspace dependency paths in the generated .pnp.cjs now use forward slashes.

Performance
  • pnpm now uses less memory when installing a package whose archive is larger than 64 MiB unpacked, and when installing a runtime from a zip archive, such as Node.js on Windows, Deno, or Bun #​14164.

  • A fresh install reusing a warm global virtual store skips reimporting packages whose target directory is already complete #​11112.

  • A warm pnpm install reuses on-disk package metadata for five minutes when the registry does not send an ETag. Registries that send an ETag, including the public npm registry, still revalidate with a conditional request. pnpm update still fetches current metadata #​13976.

Patched dependencies
  • pnpm install now repairs a pnpm-lock.yaml whose (patch_hash=<hash>) dependency paths disagree with its patchedDependencies map, including paths that lack the hash their patch calls for. pnpm previously accepted such a lockfile as up to date and kept the old patched files. pnpm install --frozen-lockfile now fails on such a lockfile with ERR_PNPM_INCONSISTENT_PATCH_HASH. It fails with ERR_PNPM_UNCHECKABLE_PATCH_HASH when a patch hash in the lockfile is malformed, or when the lockfile lacks the package version or patch entry that the check needs #​15336.

  • pnpm install now fails with ERR_PNPM_PATCH_NOT_FOUND when a patch file listed in patchedDependencies does not exist. It used to fail with a raw ENOENT error and a stack trace #​5268.

  • pnpm now fails with ERR_PNPM_INVALID_PATCHED_DEPENDENCY when patchedDependencies has an invalid shape or contains a non-string value.

  • engineStrict now checks the patched package.json when a patchedDependencies entry changes engines. A patch that relaxes engines.node no longer fails the install against the published range #​9603.

  • pnpm patch now applies the existing patch file to the edit directory of a git-hosted dependency, as it already does for packages from the registry #​9699.

  • pnpm patch-commit now fails with an error when git cannot be found in PATH. It previously reported that no changes were found #​8666.

Workspaces and filtering
  • pnpm install refreshes injected copies of workspace packages when source projects are rebuilt. Injected copies previously stayed stale until pnpm install --force #​4407.

  • Scripts listed in syncInjectedDepsAfterScripts now update injected dependencies while they run. A watcher on the injected package, such as a dev server, sees each change before the script exits #​4410.

  • pnpm install no longer fails for an injected workspace dependency whose package publishes from a publishConfig.directory that its own prepare script builds. The injected copy now picks up that directory once prepare finishes building it. pnpm install --frozen-lockfile no longer reports the dependency as outdated while the directory has not been built yet #​7811.

  • With sharedWorkspaceLockfile: false, an injected workspace package that has lifecycle scripts is now hard linked into the projects that depend on it. Before, pnpm left a plain copy, so later edits to the package did not reach those projects #​9828.

  • injectWorkspacePackages now hard links a workspace dependency declared with a relative path, such as workspace:../foo, the same way it already does for workspace:* #​10446.

  • pnpm install no longer creates a node_modules symlink inside the publishConfig.directory of a workspace package linked with linkDirectory. A build tool that cleaned its output directory through that symlink deleted the files of the package's dependencies. pnpm install also removes a symlink that an earlier install left there #​16226.

  • When verifyDepsBeforeRun triggers an install before a filtered pnpm run or pnpm exec, pnpm now installs only the selected projects and their dependencies. A later filtered command also installs a selected project that an earlier filtered install skipped #​11865.

  • pnpm import in a workspace now keeps the versions pinned by a yarn.lock inside a workspace project #​4385.

  • Installing with pnprServer set now records the pnpmfile checksum in the lockfile, so a later pnpm install --frozen-lockfile accepts that lockfile. A frozen install through the pnpr server now fails if the pnpmfile changed. If the pnpmfile defines a readPackage, afterAllResolved or preResolution hook or custom resolvers, pnpm resolves dependencies locally and prints a warning that the pnpr server was not used #​14460.

    Installing through a pnpr server now links a workspace project at the directory its publishConfig.directory names. An install that resolves through a server which does not forward the setting fails with ERR_PNPM_PNPR_PUBLISH_DIRECTORY_MISMATCH. The server rejects a publishConfig.directory that points outside its project.

Adding, updating, and removing dependencies
  • With autoInstallPeers, pnpm add and pnpm remove in a workspace project keep the locked version of a peer dependency the project declares. In a workspace where another project depended on a different version of that package, the peer could switch to that version #​11225.

  • Adding a dependency now keeps unrelated transitive dependencies on their locked versions #​11456.

  • pnpm update --recursive <pkg> no longer changes the version of a peer dependency that another workspace project installs automatically. Such a peer could move to a version outside the range the project declares, for example to React 19 in a project that declares react: ^18.3.1 #​14928.

  • pnpm update package@beta on a dependency declared as catalog: now updates the catalog entry and keeps catalog: in package.json. Before, pnpm wrote the resolved specifier to package.json #​13399.

  • pnpm update now applies an override that references a catalog with the catalog's new value when the update bumps that catalog entry. Before, the packages the override targets kept the old version in the lockfile #​12159.

  • pnpm add <dir> now warns when the added directory declares peer dependencies, as pnpm link does. The directory is saved as a link: dependency, and its peers are not resolved from the project that adds it. Use the file: protocol to have them resolved #​5523.

Running scripts and commands
  • pnpm run and pnpm exec no longer install dependencies automatically when the root package.json still keeps overrides, packageExtensions, patchedDependencies, or ignoredOptionalDependencies in its pnpm field. pnpm no longer reads that field, so the install rewrote the lockfile without those settings. The command now fails and asks to move the settings to pnpm-workspace.yaml #​16278.

  • pnpm run no longer reinstalls dependencies when a node_modules directory installed outside CI is used with CI=true, or the other way around #​12337.

  • pnpm no longer hangs after a lifecycle script exits while a process it started in the background keeps the script's output open. pnpm stops reading that output one second after the script exits #​5730.

  • A signal sent to pnpm, such as SIGTERM, now reaches the pnpm that pnpm switches to because of packageManager or devEngines.packageManager, and the one that pnpm with runs. The signal used to be dropped, so scripts running under that pnpm never got to shut down #​9948.

  • pnpm run exits with the code of a script that handles Ctrl+C and shuts down. A script that finished cleanly is not reported as a lifecycle failure. The commands after it in the same script still run #​9945.

  • pnpm run and lifecycle scripts use the configured scriptShell, including Git Bash on Windows, when shellEmulator is also enabled. shellEmulator still runs scripts when scriptShell is not set. Extra arguments passed to pnpm run are quoted for the shell that runs the script, so a Windows path stays intact #​14719.

  • pnpm -r run /regexp/ now honors the tasks dependsOn declared for each script the selector matches, like running the script by name does. Matched scripts that depend on each other run in order. Each matched script runs once #​15596.

  • Commands run from a POSIX shell through a dependency's own node_modules/.bin, such as node_modules/vite/node_modules/.bin/esbuild, no longer fail with MODULE_NOT_FOUND #​10189.

  • pnpm rebuild with nodeLinker: hoisted no longer puts one package's parent node_modules/.bin directories on the PATH of the packages it builds after it.

Publishing, packing, and deploying
  • pnpm publish now waits at least 5 minutes for the registry to answer a publish request, like npm. This fixes "409 Conflict - Failed to save packument" errors when the registry is slow to answer #​11454.

  • pnpm deploy with a shared lockfile now copies workspace dependencies into the deploy directory, even when packageImportMethod is set to hardlink. Previously, their files were hard-linked to the workspace sources, so editing a source file also changed the deployed copy #​12176.

  • pnpm deploy --prod no longer fails with ERR_PNPM_OUTDATED_LOCKFILE when the deployed project declares a devEngines.runtime with onFail: download. The runtime stays out of the deployed node_modules with the rest of the dev dependencies #​15703.

  • pnpm deploy --legacy no longer leaves broken links to nested local dependencies of workspace packages #​9575.

  • pnpm deploy no longer creates extra directories inside the deploy target and workspace projects when using a relative deploy path #​10981.

Manifests and configuration files
  • Settings given on the command line, such as --registry and --store-dir, now take precedence over the values a pnpmfile updateConfig hook sets #​14063.

  • An updateConfig hook that returns registriesByScope without the default or @jsr entry no longer crashes the install with Invalid URL. A missing default keeps the configured registry, and a missing @jsr falls back to the built-in JSR registry #​15619.

    The hook's registry and the default entry of its registriesByScope now set one default registry, which installs, pnpm publish, and pnpm login all use. If a hook changes both, registry wins. A route that is not a string fails with ERR_PNPM_INVALID_UPDATE_CONFIG_RESULT.

  • An updateConfig hook in .pnpmfile.cjs has to use config.registriesByScope, config.registriesByPrefix, and config.registryOptionsByUrl. These registry lookups were renamed in pnpm 11.23.0 from config.registries, config.namedRegistries, and config.registryOptions #​15620.

  • An async updateConfig hook that resolves to undefined now fails with ERR_PNPM_CONFIG_IS_UNDEFINED, as a synchronous hook that returns undefined already did.

  • pnpm config set --location=project and pnpm config delete --location=project, run from a package inside a workspace, now write settings that belong in pnpm-workspace.yaml to the workspace root's pnpm-workspace.yaml. Before, they created a new pnpm-workspace.yaml in the current package, which made that package the workspace root. Settings stored in .npmrc are still written to the current directory #​13757.

  • pnpm now reads the workspace directory override from PNPM_CONFIG_WORKSPACE_DIR, like other settings. NPM_CONFIG_WORKSPACE_DIR still works as a fallback #​16275.

  • A ${VAR} placeholder in .npmrc or pnpm-workspace.yaml whose name matches a built-in object property, such as ${toString}, is now treated as an unset variable. It used to be replaced with the source text of a JavaScript function.

  • pnpm now rejects a falsy non-array packages field in pnpm-workspace.yaml, such as packages: false, with an error. It used to treat the field as omitted.

Global packages, pnpm versions, and runtimes
  • pnpm update --global now reinstalls the global packages that pnpm 10 installed into the previous global directory, <global-dir>/5, so their commands are linked into the pnpm home bin directory again and pnpm list --global lists them. Once every package is migrated, pnpm deletes the previous directory and the commands pnpm 10 linked into the pnpm home #​11528.

  • pnpm env remove --global deletes Node.js versions that pnpm installed into its own store, including when another tool installed pnpm #​8357.

  • pnpm self-update no longer suggests a downgrade when minimumReleaseAge holds back the registry's latest release. It now says that release is still within the cutoff #​12006.

  • @pnpm/exe no longer ships a binary for arm64 musl Linux, such as Alpine on ARM. The published binary crashed with a segmentation fault at startup. Installing @pnpm/exe on that platform now fails with an error that suggests npm install -g pnpm or pnpm 12 #​10443.

  • The macOS and Linux release archives no longer include Windows-only files, such as node-gyp.cmd and the fastlist executables #​11352.

Windows and WSL
  • On Windows, pnpm run now passes the arguments after the script name to the script as typed. Before, cmd expanded %VAR% in them and backslashes arrived doubled. Line breaks still arrive as the two characters \n, because cmd cannot pass them. The command line pnpm prints for the script quotes the arguments the same way on every platform #​16257.

  • On Windows, command shims now run tools whose paths contain non-ASCII characters #​6999. The PowerShell shims do so in Windows PowerShell 5.1 too #​16217.

  • On Windows, the .cmd command shims in node_modules/.bin now keep a % in the project path. Before, cmd.exe expanded it as a variable reference, so the command received a mangled NODE_PATH #​15716.

  • Bin shims in node_modules/.bin run from Cygwin on Windows again. The shims passed a /cygdrive/c/... path to the Windows node found on PATH, so Node.js failed with Cannot find module 'C:\cygdrive\c\...' #​12845.

  • pnpm setup no longer writes the pn.ps1, pnpx.ps1, and pnx.ps1 PowerShell wrappers. It also removes the ones an earlier setup wrote. PowerShell now runs pn, pnpx, and pnx through their .cmd wrappers, like pnpm itself. Before, these aliases failed with a "not digitally signed" error wherever the execution policy blocks unsigned scripts #​8444.

  • On Windows, globally installed @pnpm/exe commands now run in the invoking PowerShell console and return their exit status #​6503.

  • On Windows, installing @pnpm/exe with npm inside a project now writes node_modules/.bin shims that run the standalone executable #​15688.

  • On Windows, pnpm env use -g and pnpm add -g node@runtime:<version> now replace a node.exe in the global bin directory that is a broken symlink. Previously they failed with ENOENT #​5411.

  • On Windows, pnpm expands nested %VAR% references in PNPM_HOME and the other directory environment variables it uses for its home, store, cache, state, and config directories. pnpm fails with an error when a %VAR% reference remains after expansion #​13236.

  • On Windows, if the global bin directory is not in PATH and a PATH entry still contains an unexpanded variable such as %PNPM_HOME%, the error now names that entry. A variable referenced from the user Path must be set to a full path and stored as a plain string (REG_SZ) for the entry to expand #​5283.

  • On Windows, pnpm setup no longer garbles non-ASCII characters in existing Path entries #​6346.

  • On Windows, pnpm setup repairs the PNPM_HOME registry type left by older pnpm versions, even when the configured directory has not changed.

  • On Windows, the ERR_PNPM_BAD_ENV_FOUND error of pnpm setup now shows the value PNPM_HOME is currently set to. It used to show the directory pnpm wanted to set.

  • On Windows, pnpm install no longer skips a dependency's build script on a later install when the script changes nothing inside the package directory #​15667.

  • On Windows, pnpm now retries writing the workspace state file while another process, such as an antivirus scanner, briefly holds it open #​14550.

Inspecting dependencies
  • pnpm licenses list now reports the actual on-disk package locations when using nodeLinker: hoisted or shamefully-hoist: true #​8589. pnpm licenses list --json now includes every installed copy of a package in its paths array, including hoisted copies and isolated installations with different peer dependencies. Its paths also exist on disk when the isolated linker uses a custom modulesDir.

  • pnpm list now shows the correct path of a link: dependency that points to a directory on another drive on Windows. The path used to be appended to the project directory, such as C:\project\D:\lib, and pnpm list --long could not show the package's details #​10362.

  • pnpm root now prints the configured modulesDir. It used to print node_modules regardless of the setting. A project's own modulesDir from packageConfigs is printed too #​9113.

  • pnpm audit and pnpm audit signatures now fail with an error when the lockfile contains unresolvable dependency references #​13638.

Output and messages
  • With the default and append-only reporters, installs with --loglevel warn or --loglevel error now print the full output of a failed install script. The output of successful scripts, including the root project's own install hooks, stays hidden. With --loglevel warn, pnpm also prints ignored build script warnings.

  • The lockfile verification error now suggests relaxing the policy that flagged an entry only if a fresh resolution still fails and you trust the affected packages. Errors from checks that no policy controls, such as a missing tarball integrity, no longer suggest relaxing a policy #​14411.

  • pnpm run --recursive now prints GitLab CI collapsible sections that GitLab recognizes. The section markers used to appear as raw text in the job log.

  • Local tarball dependencies using the file protocol are no longer counted as downloaded in the progress banner #​1103.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.28.0: pnpm 11.28

Compare Source

pnpm 11.28.0 adds the forceIgnoresPlatform setting and pnpm update --peer, and fixes many bugs in pnpm deploy, --filter, nodeLinker: hoisted, and custom modulesDir setups. This release also carries security fixes for shell completion, bin shims on Nix, lifecycle scripts inside a custom modulesDir, and userAgent placeholders in pnpm-workspace.yaml.

Minor Changes
  • Added the forceIgnoresPlatform setting. When it is false, pnpm install --force skips optional dependencies whose os, cpu or libc do not match the host instead of installing all of them. The default stays true #​6133.
Patch Changes
Security
  • pnpm no longer expands environment variables in a userAgent set in a project's pnpm-workspace.yaml. A userAgent with a placeholder in that file is now ignored. Before this fix, pnpm sent the variable's value to the configured registry #​15415.

  • pnpm no longer treats packages inside a custom modulesDir as workspace projects, including one that packageConfigs sets for a project. Before, with a modulesDir such as vendor and a packages pattern such as **, a repeat install ran the lifecycle scripts of dependencies that allowBuilds had not approved #​15412.

  • On Nix, a dependency's bin named like a system utility such as sed can no longer redirect a POSIX bin shim or the pnpm, pn, pnpx, and pnx launchers. The shims and launchers now ignore node_modules and relative PATH entries while they locate their own files. Installing again replaces the shims already in node_modules #​14883.

  • Shell completion now omits candidates containing control or invisible formatting characters, and fish completion omits names containing backslashes. Package and script names can no longer inject extra completion records or terminal escape sequences.

  • Commands that run pnpm again, such as pnpm runtime set and pnpm env use, no longer re-run a script that only looks like pnpm. A script named pnpm or pn that another package installed was run as though it were pnpm.

  • pnpm store prune now leaves a dlx cache root that is a symlink or Windows junction untouched. Cleanup no longer removes directories through that link.

Installing packages
  • pnpm install now fails at once when a registry or tarball server presents a TLS certificate that fails verification, such as a self-signed or expired one. The error names the certificate problem. Such requests were retried for more than a minute #​9134.

  • pnpm install no longer appears to hang when a git dependency is fetched over SSH and ssh asks for a key passphrase or a host key confirmation. pnpm now runs ssh in batch mode, so the install fails right away with the ssh error, and a key that needs a passphrase has to be loaded into an SSH agent first. An ssh command selected through GIT_SSH_COMMAND, GIT_SSH, or the core.sshCommand git setting is kept as is #​2227.

  • pnpm no longer crashes on startup when the temporary directory set by TMPDIR, TEMP, or TMP does not exist #​4960.

  • pnpm install --silent no longer fails when the install is delegated to pacquet. pnpm also stops passing -s, --loglevel and the other reporting flags to pacquet #​11936.

  • Fixed pnpm install failing with EEXIST when a concurrent install cleared the file or directory that was occupying a symlink path. On Windows, a symlink another process is still holding is no longer moved aside and recreated.

  • pnpm install no longer fails when writing the workspace state file encounters an error. Failures to update the state file now emit a warning instead of aborting the install #​14550.

  • Installing or adding dependencies no longer fails when a previously installed local tarball file was deleted from disk #​8367.

  • pnpm install now reads the same local tarball it installs when a dependency's absolute file: path contains ... Such a path could install a different tarball than the one it read, failing with ERR_PNPM_TARBALL_INTEGRITY, or fail to resolve at all.

  • pnpm install --frozen-lockfile now rejects changed local tarballs, even when the previous archive contents are in the store #​1889.

  • pnpm add and pnpm install now support installing bzip2 compressed tarballs #​6761.

  • pnpm install now fetches committed submodules of git dependencies #​1470.

  • Interrupting pnpm install with Ctrl+C or SIGTERM no longer leaves a temporary lockfile (.pnpm-lock.yaml.*.tmp) behind in the project #​1418.

  • pnpm install and pnpm run now reinstall a single project that was moved or renamed together with its node_modules. Before, they reported "Already up to date" while links such as Windows junctions still pointed at the old location #​9512.

  • pnpm install now relinks a direct dependency whose link in node_modules points to a missing target. Before, it reported "Already up to date" and left the broken link #​9758.

  • pnpm install and pnpm add no longer skip optional dependencies that the Node.js version resolved for a devEngines.runtime range supports, when the range uses onFail: download. An explicitly set nodeVersion still takes priority #​14628.

  • pnpm install now uses the running Node.js when devEngines.runtime declares a range without onFail: download. Optional dependencies supported by the active Node.js are no longer skipped #​15230.

  • pnpm install --engine-strict now respects engines relaxed by readPackage hooks in .pnpmfile.cjs #​15482.

  • pnpm install now applies changes to or removal of a global readPackage hook when an existing lockfile is present #​15136.

  • The project's .pnpmfile.mjs or .pnpmfile.cjs now runs after the pnpmfiles of config dependency plugins #​9891.

  • A readPackage hook that sets a dependency range to a value other than a string, such as undefined, now fails the install with an error that names the dependency, the package, and the pnpmfile. Delete the property to remove a dependency #​5517.

  • pnpm install --prod and other installs that skip devDependencies no longer run the pnpm:devPreinstall script #​7065. They skip prepare lifecycle scripts too, as does pnpm install given package arguments. pnpm deploy does not run the prepare scripts of the deployed project #​7282.

  • The root project's preinstall script now runs before dependencies are resolved and linked. A guard such as npx only-allow yarn can stop the install before pnpm populates node_modules #​3760.

  • pnpm install --prod, pnpm fetch --prod and pnpm deploy --prod no longer install a devDependency that is only there to satisfy an optional peer dependency of a production dependency. pnpm list, pnpm why, pnpm licenses, pnpm sbom and pnpm audit leave it out of --prod results too. The same applies to --dev. A peer that is not optional is still installed and audited #​15344.

  • pnpm prune --prod and production installs now prune excluded development dependencies even when lockfile generation is disabled.

  • pnpm fetch now also installs the pnpm version that pnpm-lock.yaml pins, when it differs from the running pnpm. A later pnpm install --offline that switches to the pinned version no longer fails because that version is missing from the store #​11808.

  • A dependency that ships a binding.gyp and sets gypfile: false no longer gets the node-gyp rebuild install script pnpm synthesizes for it. Such a dependency needs no allowBuilds entry and is no longer listed under "Ignored build scripts".

  • pnpm install no longer adds allowBuilds placeholder entries to pnpm-workspace.yaml when it runs in CI or without a terminal. Interactive installs still add them #​11574.

  • Installing through a pnpr server now installs a project's peer dependencies when autoInstallPeers is enabled. A project that declared only peer dependencies failed with ERR_PNPM_OUTDATED_LOCKFILE or skipped its peers #​14833.

Resolving and linking dependencies
  • pnpm now installs a dependency that a package also declares as an optional peer dependency, for example lightningcss in some vite builds. The dependency was missing from node_modules, so the package failed to import it #​8912.

  • Removal overrides such as "parent>peer": "-" now prevent optional peers from being installed from another workspace package #​15008.

  • Removing an entry from overrides now re-resolves the packages it targeted. A version the override had locked is no longer kept just because the declared range still accepts it #​4587.

  • packageExtensions and overrides entries with a ranged selector (such as @<X or @*) no longer match a dependency that has no package.json, such as a local directory dependency #​15007.

  • Trim leading and trailing whitespace from dependency override selectors in pnpm.overrides #​6356.

  • With trustPolicy: no-downgrade, pnpm now resolves the newest matching version that is not a trust downgrade. Previously a dependency failed with ERR_PNPM_TRUST_DOWNGRADE even when an older version satisfied its range. pnpm self-update picks its target version the same way. A request for an exact version still fails #​14176.

  • pnpm install and pnpm update now resolve a dependency range to the newest matching version that is not deprecated. A version already recorded in the lockfile is still used #​15128.

  • pnpm add and pnpm remove no longer move unrelated transitive dependencies to other versions. Adding a package and then removing it now leaves pnpm-lock.yaml unchanged. Before, the dependencies of auto-installed peers and npm: aliased subdependencies could move to a newer version that was already in the lockfile #​11859.

  • pnpm dedupe now moves transitive dependencies to the version a catalog: dependency pins, as it already did for versions written directly in package.json.

  • pnpm install --ignore-pnpmfile no longer removes pnpmfileChecksum from an up-to-date pnpm-lock.yaml. pnpm install --frozen-lockfile --ignore-pnpmfile no longer fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH when the lockfile records a pnpmfileChecksum. A command that resolves dependencies with the pnpmfile ignored still writes the lockfile without it #​10944.

  • pnpm install --frozen-lockfile now succeeds when an optional dependency was unresolvable and skipped by the install that wrote the lockfile. Previously, frozen installs failed with ERR_PNPM_OUTDATED_LOCKFILE. The notice states that the dependency could not be resolved and names the requested range #​3960.

  • pnpm no longer rewrites packageManagerDependencies in pnpm-lock.yaml when that block pins @pnpm/exe beside pnpm. The rewrite ran on every command, so pnpm list left a clean working tree dirty, and pnpm version then refused to run #​14926.

  • pnpm import and fresh resolutions now record integrity for git-hosted tarballs, such as codeload.github.com URLs, even when the tarball is already in the store #​13338.

  • Merging lockfiles now preserves recorded configuration fields such as overrides, neverBuiltDependencies, patchedDependencies, packageExtensionsChecksum, settings, and catalogs #​8366.

  • A lockfile entry whose resolution is unchanged now keeps its recorded deprecated message #​5772.

  • pnpm no longer writes a package's legacy array-form engines, such as ["node >= 0.8"], to the lockfile. It was recorded as an object keyed by index, such as {'0': node >= 0.8} #​4518.

  • With nodeLinker: hoisted, hoistWorkspacePackages now links each workspace project that hoistPattern or publicHoistPattern selects into the root node_modules, unless a hoisted package or a root dependency already uses its name. The project's bins are linked into the root node_modules/.bin #​7553.

  • Workspace projects that hoistPattern or publicHoistPattern selects are now hoisted on every install. A project added to the workspace was not hoisted until node_modules was deleted and reinstalled. A workspace that installs nothing from a registry hoisted none of its projects at all #​3642.

  • With nodeLinker: hoisted, pnpm install now removes the commands of the packages it removes from node_modules/.bin, such as a nested copy deduped into the root node_modules #​7568.

  • pnpm install now links a dependency's bin even when the bin's file does not exist yet, such as a workspace package's bin that a build script creates after install. Previously pnpm printed a Failed to create bin warning. The command then stayed missing until node_modules was removed #​10007, #​10216.

  • Executable linking now makes a bin executable for every user. A target with only some execute permission bits set was left non-executable for other users #​3699. Bin linking leaves workspace and linked dependency files outside node_modules unchanged.

  • Dependencies and executable binaries are now correctly linked and accessible for workspace packages using publishConfig.directory and publishConfig.linkDirectory #​8338.

Workspaces and filtering
  • Fixed pnpm install for workspace projects reached through a symlink, such as a packages directory that links to a folder outside the workspace. pnpm now installs their dependencies, and the links in their node_modules resolve #​1044.

  • A dependency declared with catalog: now counts as a workspace dependency when its catalog entry points at a workspace project, for example workspace:* #​15587. With linkWorkspacePackages enabled, so does an npm: alias of a workspace project, such as "math-alias": "npm:math@^1.0.0". pnpm -r run runs that project first. --filter <pkg>... selects it.

  • A workspace: dependency now resolves to a workspace project whose version is not valid semver, such as 1 or 1.0. workspace:*, workspace:^, and workspace:~ match it. A range identical to the version also matches it #​4567.

  • A workspace: dependency with an exact version now resolves to a workspace project whose version carries SemVer build metadata. For example, workspace:0.5.6-next.3 matches a project at 0.5.6-next.3+f60facc #​6483. A workspace project with build metadata is no longer skipped when it matches the requested range and has the same version precedence as the registry package #​2812.

  • Secondary dependencies now prefer the version resolved by the local project's direct dependencies over versions from sibling workspace projects #​7191.

  • pnpm install now re-resolves a workspace project's auto-installed peer dependency when another workspace project changes its specifier for that package to one that excludes the locked version but still overlaps the peer range. The peer then resolves to the version a fresh install would pick #​11800.

  • pnpm install --frozen-lockfile now fails with ERR_PNPM_OUTDATED_LOCKFILE when pnpm-lock.yaml lists a workspace project whose directory or manifest file is missing. The install used to report success without installing that project's dependencies #​7667.

  • pnpm install --frozen-lockfile now fails when a workspace package's version no longer satisfies the range that a dependent workspace project declares for it. This includes injected workspace dependencies #​7823.

  • pnpm install -r now installs every workspace project when recursiveInstall is set to false in pnpm-workspace.yaml #​7504.

  • pnpm install with --filter now installs only the dependencies of the selected projects when using nodeLinker: hoisted #​8882.

  • pnpm install now updates an injected workspace dependency after that package's own dependencies change, when shared-workspace-lockfile is false #​7209.

  • syncInjectedDepsAfterScripts now copies files into injected dependencies when node_modules is on another filesystem than the package sources. The sync previously failed with a cross-device link error and made the script run exit with an error #​14703.

  • Fixed injected workspace dependency synchronization failing with EPERM on Windows when removing nested directories.

  • Workspace discovery now returns one project per directory when multiple manifest formats are present. It selects package.json, then package.json5, then package.yaml #​3027.

  • Wildcards in negated packages patterns of pnpm-workspace.yaml now match directories whose names start with a dot. For example, !packages/** now also excludes packages/.dev/tool when another pattern includes .dev explicitly.

  • pnpm now warns when a workspace install covers a project that has its own pnpm-workspace.yaml. The nested file's settings, such as patchedDependencies, do not apply when the outer workspace installs that project. pnpm reads settings only from the pnpm-workspace.yaml at the workspace root #​11724.

  • pnpm now warns when shared-workspace-lockfile is passed on the command line outside a workspace #​1617.

  • The [<since>] filter selector now compares against the commit where the current branch forked from <since>. Projects changed only by newer commits on <since> are no longer selected. Uncommitted changes are still included. In a shallow clone without that commit, pnpm compares against <since> directly, as before #​9907.

  • --filter "[<since>]" now selects workspace packages when dependency versions change in a catalog in pnpm-workspace.yaml #​8718. It also selects projects that files were moved out of when git detects the move as a rename #​15481.

  • --filter now evaluates selectors in order, so later inclusion filters can re-include packages that an earlier exclusion filter excluded #​9354.

  • Directory filters such as --filter=./packages/* now select projects when the current directory was entered with a lowercase drive letter on Windows, like c:\repo #​5500.

Custom modulesDir
  • pnpm run, pnpm exec, pnpm version hooks, and the lifecycle scripts a project runs during install now find commands in a custom modulesDir, and bin shims resolve dependency paths there #​3604. Project .hooks scripts are read from the configured modules directory. Installs resolved by pnpr now preserve configured modules and executable directories. pnpm bin now reports the configured executable directory. In a workspace whose projects keep their own lockfiles, a packageConfigs entry that gives one project its own modulesDir is followed too.

  • Tools installed in a custom modulesDir can load CommonJS plugins installed there, the same way they would from node_modules. When executables are symlinks, as with preferSymlinkedExecutables or the hoisted linker, this works for pnpm run, pnpm exec, pnpm version hooks, and the lifecycle scripts a project runs during install. A symlinked tool started directly from a shell does not get it. Paths containing the platform path-list separator do not receive this fallback. extendNodePath: false disables this fallback #​3604.

  • A repeat pnpm install in a workspace with a custom modulesDir now takes the up-to-date fast path. Before, pnpm looked for each workspace project's dependencies in node_modules and ran a full install every time.

Adding, updating, and removing dependencies
  • pnpm add now keeps the specifier a readPackage hook provides when the hook rewrites the requested one. When the hook removes the dependency instead, the add skips it and reports why. Previously the add wrote the request either way, and the hook undid it on the next read, so pnpm install --frozen-lockfile failed #​15156.

  • pnpm add now saves changes to package.json before running lifecycle scripts, so a postinstall script failure leaves the added dependency in package.json #​8627.

  • pnpm add now saves the requested exact version when adding a dependency, even when the manifest already contains a version range #​6040.

  • pnpm add and pnpm install keep an empty peerDependencies, dependencies, devDependencies, or optionalDependencies field that was already in package.json. pnpm still drops such a field when it removes the last entry itself, as pnpm remove does #​5096.

  • Added a --peer flag to pnpm update to update ranges in peerDependencies #​8081.

  • pnpm update now keeps a version range whose shape has no save prefix, such as <= 3.0.0 or >=1.0.0 <2.0.0, when the updated version still satisfies it. Before, <= 3.0.0 became ^3.0.0 #​6714.

  • pnpm update <name> now updates a peer dependency that pnpm installed automatically #​10486.

  • pnpm update <pkg> now moves a package off a locked version the registry no longer serves, such as an unpublished release. The lockfile check for supply-chain policies such as minimumReleaseAge used to reject that version before the update could replace it #​9953.

  • pnpm update --prod no longer installs devDependencies when run in a project installed with --prod #​8038.

  • pnpm update --interactive --workspace now allows external dependencies to be updated.

  • pnpm outdated and pnpm update now apply minimumReleaseAge to GitHub Actions. minimumReleaseAgeExclude entries match action names such as actions/checkout #​13923.

  • pnpm remove now runs the project's own preuninstall, uninstall, and postuninstall scripts. preuninstall and uninstall run before dependencies are unlinked. A failure in either stage aborts the removal. postuninstall runs after unlinking completes. The ignoreScripts setting and --lockfile-only skip all three stages #​3276.

  • pnpm remove -r now fails if any requested dependency is absent from all selected workspace projects. Validation respects --save-prod, --save-dev, and --save-optional and completes before modifying project manifests #​2319.

  • pnpm remove now accepts --trust-lockfile and --no-trust-lockfile to control supply-chain policy checks while removing a package #​14406.

  • pnpm unlink now removes the link: dependency that pnpm link <dir> added to package.json. The linked package is removed from node_modules and the lockfile. A link: dependency to another directory is kept #​4219.

  • minimumReleaseAgeExcludePrune and trustPolicyExcludePrune now work in workspaces with shared-workspace-lockfile=false. Once every project has been installed, pnpm drops an entry only if no project lockfile records it. Undecided allowBuilds entries are pruned the same way #​14612.

  • pnpm import now converts dependencies that use Yarn's patch: protocol. The dependency keeps the version it patches, and the patch file is added to patchedDependencies in pnpm-workspace.yaml. If the patch file is missing, pnpm prints a warning and imports the dependency without the patch #​10278.

  • pnpm import in a workspace now keeps the versions pinned by the root yarn.lock, package-lock.json, or npm-shrinkwrap.json when another workspace project's range allows a newer version. Before, the root project got the newest version in its range #​4385.

  • pnpm patch-commit now resolves default patch directory locations when passed a package name or package specifier (such as pnpm patch-commit <pkg> or pnpm patch-commit <pkg>@<version>).

  • pnpm patch-commit now updates the lockfile snapshot and prunes removed dependencies when the patch modifies package.json #​6866.

  • pnpm patch-commit now falls back to copying package files when hard linking fails.

  • make-dedicated-lockfile no longer removes fields such as main and types from the publishConfig of the project's package.json. It now restores package.json when it cannot move the original node_modules back to its place. The error then names .tmp_node_modules, where the original node_modules was left. The command refuses to run while that directory exists, so a retry cannot overwrite it.

Running scripts and commands
  • A script that pnpm runs without a terminal now ends when pnpm itself is killed. Killing pnpm's process group, as Playwright's webServer does to stop the command it started, used to leave the script running and holding the caller's output pipes open #​15555.

  • pnpm --filter <project> <command> and pnpm -r <command> now run a command installed in the selected projects' dependencies when none of them has a script by that name. This matches pnpm <command> in a single project. pnpm run with --filter or -r still reports the missing script #​10151.

  • pnpm exec and pnpm dlx now set npm_execpath, INIT_CWD, npm_node_execpath, and NODE for child processes #​7037. Scripts that pnpx and pnx run now get pnpm itself as npm_execpath. A script that ran $npm_execpath install there ran pnpm dlx install.

  • pnpm exec now sets the PWD environment variable to the directory the command runs in. Shells and tools that read PWD now report the logical path of a workspace package reached through a symlink #​1550.

  • A script that runs pnpm run no longer adds duplicate node_modules/.bin and node-gyp-bin entries to PATH #​5352.

  • Concurrent pnpm run and pnpm exec commands now serialize their dependency installs #​14551.

  • pnpm run --recursive no longer reports interrupted scripts as lifecycle failures after Ctrl+C.

  • pnpm restart now runs the "stop" and "start" scripts when the package has no "restart" script. Previously it ran "stop" and then failed with "Missing script: restart" #​4750.

  • pnpm install-test now accepts --no-bail when executed directly and in recursive runs #​3777.

  • pnpm dlx now keeps a separate cache entry for each Node.js major version. A package built under one Node.js major version, such as a native addon, is no longer reused under another #​8611.

  • A runtime: version range that contains || or a space, such as a devEngines.runtime version of ^22.18.0 || ^24.0.0, now installs the requested runtime. pnpm used to install the npm package with the same name, such as node #​14817.

  • When the configured scriptShell does not exist, running a script now fails with an error that names the shell. Previously pnpm printed only an exit code or the package directory #​7562.

  • If a script is killed by a signal that pnpm survives, such as SIGPIPE, the error now names the signal: Command failed with signal SIGPIPE. #​9821.

Publishing, packing, and deploying
  • pnpm publish now resolves workspace: dependencies from workspace manifests when node_modules is not installed. Previously, publishing without node_modules failed with ERR_PNPM_CANNOT_RESOLVE_WORKSPACE_PROTOCOL #​6567.

  • pnpm publish now honors publishConfig["@scope:registry"] for a package in that scope. It takes precedence over the registry set for the same scope in .npmrc and over publishConfig.registry #​12071.

  • pnpm pack and pnpm publish now include bundled dependencies when using the isolated linker. This covers workspace packages and the dependencies of each bundled package. Bundled dependencies are also included when publishConfig.directory selects a build directory #​1643.

  • pnpm pack, pnpm deploy, and installs of local directory dependencies now keep symlinks that point to files or directories included in the package. pnpm pack leaves out symlinks that point outside the package #​8208.

  • pnpm pack now honors the files field of package.yaml and package.json5 manifests. Git-hosted and injected local dependencies that use these manifests now honor it too #​7906. The archive includes exactly one package.json when the project uses an alternative manifest format, even when .npmignore or files excludes the source file.

  • pnpm pack now preserves file executable permissions in the packed tarball when source files are executable on disk.

  • pnpm publish and pnpm pack now report a missing version or name field on a workspace dependency. Previously, pnpm reported that the dependency was not installed #​4164.

  • pnpm publish and pnpm pack now report an error when a bin script has a shebang line ending with CRLF #​7311.

  • pnpm deploy now copies the packageManager and devEngines.packageManager fields of the workspace root package.json into the deployed package.json, unless the deployed project pins a package manager itself #​9079.

  • pnpm deploy now puts the virtual store at virtualStoreDir, resolved against the deploy directory. A shared-lockfile deploy records virtualStoreDir in the deployed pnpm-workspace.yaml. With the global virtual store enabled or an absolute virtualStoreDir, the deploy still uses node_modules/.pnpm #​8787.

  • pnpm deploy now respects --package-import-method passed on the command line and reports the package import method correctly #​7593.

  • pnpm deploy no longer triggers an install when running scripts in a read-only deployed filesystem #​11617.

  • A legacy pnpm deploy with node-linker=hoisted now puts the deployed project's direct dependencies at the top of the deployed node_modules #​9671.

  • pnpm deploy --legacy no longer rewrites node_modules/.pnpm-workspace-state-v1.json in the source workspace. The next verifyDepsBeforeRun check there reported the workspace as out of date #​15352.

Manifests and configuration files
  • Fixed pnpm version failing on projects using a package.yaml manifest.

    Fixed pnpm init creating an extra package.json when package.yaml is already present.

  • pnpm now preserves CRLF line endings when it modifies project manifests.

  • pnpm version now applies pending bumps to private workspace packages. A private package's changelog is written to its committed CHANGELOG.md, also when versioning.changelog.storage is registry #​13736, #​13519.

  • pnpm change check now validates the pending change intents in .changeset/. It fails when an intent names a package that is not in the workspace or cannot be released.

  • .npmrc files now support npm's ${VAR?} placeholder. It expands to the value of VAR, or to an empty string without a warning when VAR is unset #​14404.

  • pnpm now expands environment variables in _auth.authToken values loaded from global config.yaml and pnpm_config__auth #​12828.

  • pnpm now warns when an empty environment variable removes an .npmrc authentication token. Authentication environment warnings now name the affected key #​4806.

  • pnpm now keeps the configured default registry when _auth holds credentials for several registries and some of those registries serve package scopes.

    Lockfile verification checks a tarball hosted on a scoped registry against that registry's metadata, unless the package's own scope has a registry assigned #​15530.

  • pnpm now treats a missing global config.yaml, auth.ini, or other optional config file as absent in Node.js-compatible runtimes such as StackBlitz WebContainers. Commands such as pnpm --version failed there with ENOENT #​14030.

  • pnpm login now logs back in to an existing user on registries without web login, such as verdaccio. The classic login request sends the username and password as basic auth, as npm login does #​12055.

  • pnpm doctor now checks the configured default registry and sends its credentials. It used to always ping https://registry.npmjs.org/ #​15618.

Global packages, pnpm versions, and runtimes
  • Global commands such as pnpm add --global, pnpm list --global, and pnpm bin --global now run with the pnpm you invoked, even in a project that pins another pnpm version. Previously, a pin with onFail: "download" switched them to the pinned pnpm, and a pinned pnpm 10 or older failed because its global bin directory was not in PATH #​14531.

  • pnpm add -g, pnpm update -g, and pnpm remove -g now recover a global package group whose entire node_modules directory was deleted. pnpm remove -g leaves such a group's command shims in the global bin directory #​15093. These commands no longer fail with ERR_PNPM_PACKAGE_MANIFEST_IO_ERROR when another global package's link into the store dangles, for example after the store was pruned. The pnpm install script failed the same way on such a machine.

  • pnpm update --global now skips a global package installed from a file: path that no longer exists, prints a warning, and updates the remaining global packages. Previously the whole update failed with ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND #​12533.

  • pnpm update -g no longer asks more than once for approval of the same immature name@version when minimumReleaseAgeStrict is enabled #​15091.

  • pnpm self-update run in a project that pins pnpm through packageManager or devEngines.packageManager now also updates the global pnpm, as it does outside a project #​14747.

  • pnpm self-update no longer leaves the previous pnpm in the global packages when it was installed as @pnpm/exe. pnpm ls -g now lists a single pnpm #​14709.

  • pnpm setup no longer deletes aliases and other lines that sit between a # pnpm comment and the pnpm block in a shell startup file #​7067.

  • pnpm env remove now cleans up dangling Node.js executables and symlinks. Surviving global commands remain intact.

  • Node.js runtime resolution now supports Windows ARM64. Node.js 20 and newer resolve native win-arm64 builds, and older versions fall back to win-x64 under emulation #​7123.

Windows and WSL
  • pn, pnpx, pnx, and pnpm now run when Git Bash, MSYS2, or Cygwin launches them through a Windows path such as C:\Users\me\node_modules\pnpm\pn. The aliases used to fail to find the pnpm installed beside them, or hand the call to an unrelated one #​14884.

  • Fallback .cmd and .ps1 Windows wrappers in @pnpm/exe now propagate the exit status of the invoked pnpm command #​14826.

  • On Windows, bin shims run from Git Bash, MSYS2, or Cygwin now pass NODE_PATH to Node.js as Windows paths. A project installed from cmd or PowerShell gave its bins a NODE_PATH under the Git install directory when they ran from Git Bash. Installing again replaces the shims already in node_modules #​3360.

  • pnpm install in WSL now waits out Windows file locks on a Windows drive such as /mnt/c, as it already does on Windows. Before, an antivirus or indexer scan holding a file open could fail the install with EACCES #​6155.

  • On Windows, pnpm now retries saving pnpm-lock.yaml for up to a minute while another process holds the file open. The save used to fail at once with EPERM, EBUSY, or "Access is denied" #​9461.

  • On Windows, pnpm now fails within about a second when it cannot move a node_modules directory installed by another package manager because a file in it is in use. The error names the directory and suggests stopping the process that uses it. pnpm used to retry for a minute and then print a raw EPERM stack trace #​7505.

  • pnpm now escapes trailing dots and spaces in node_modules/.pnpm directory names. Windows strips these characters, so a dependency such as "parent-pkg": "file:../" created a directory that could not be deleted or failed to install #​8101.

  • pnpm install now resolves local tarballs specified with bare UNC paths on Windows #​1669.

  • pnpm now recognizes local paths with forward slashes on Windows.

  • On Windows, pnpm add and pnpm update now write relative file: and link: specifiers with forward slashes to package.json and the lockfile. They used to write backslashes, so the same project produced different files on Windows and on other systems #​7497, #​9687.

  • Fixed scripts failing with errors such as 'an-compile' is not recognized when scriptShell is set to cmd.exe on Windows #​7181.

Inspecting dependencies
  • pnpm audit and pnpm audit signatures now check only the dependencies of the projects selected by --filter, --filter-prod, or --workspace-root. The filter used to be ignored, so a filtered audit reported the whole workspace #​10982.

  • pnpm audit now lists at least one dependency path from every workspace project that depends on a vulnerable package. Before, a project whose dependency was reached through more than 100 paths filled the path list, and other projects that depend on the same package were left out #​12200.

  • pnpm audit --fix=update now fixes vulnerabilities in dependencies declared through an npm alias. A specifier such as "foo": "npm:vulnerable-pkg@1.0.0" moves to the patched version and keeps the alias. Versions pinned with a leading = are fixed as well #​15155.

  • pnpm audit --fix now prunes redundant overrides when one vulnerable range is a subset of another for the same package #​8577.

  • Running pnpm list inside a workspace package without --recursive or a filter now lists only the current package #​14494. pnpm licenses list does the same. Use --recursive or --filter to list the licenses of other workspace projects #​5689.

  • pnpm list --only-projects now prints every project selected with --filter or --recursive, including a project that has no workspace dependencies #​9770. It also lists the workspace projects when sharedWorkspaceLockfile is false #​7151, and a project that sets publishConfig.directory #​10635. It no longer reports packages in node_modules that are missing from the lockfile #​9528.

  • pnpm licenses list failed or reported nothing in a workspace with sharedWorkspaceLockfile: false. It now reads the lockfile of each selected project #​10140.

  • With nodeLinker: hoisted, pnpm licenses list reported paths under node_modules/.pnpm that do not exist. It now reports the directory where the hoisted linker placed each package #​8589.

  • pnpm outdated and pnpm -r outdated now fail with ERR_PNPM_NO_PACKAGE_IN_DEPENDENCIES when a requested package selector does not match any dependency in the inspected projects #​2319.

  • pnpm -r outdated --json now includes every outdated workspace dependency when multiple projects depend on different versions or dependency types of the same package. Such a package is keyed by its current version and dependency type, for example vue@2.7.14 (dev) #​7693.

  • pnpm sbom filtered to a single workspace project no longer replaces the project's own license or bugs field with the workspace root's value when the project's value is blank. The same applies to an author, description, license, repository, or bugs field set to null #​14882.

  • pnpm store status no longer reports packages with build or postinstall scripts as modified in the store. When packages were mutated, it now lists only those packages and no longer suggests running pnpm install --force #​919.

  • pnpm peers check and the ERR_PNPM_PEER_DEP_ISSUES error now group peer dependency issues under the workspace project they were found in #​15351.

  • The pnpm:peer-dependency-issues log event, which --reporter ndjson prints, no longer lists peers silenced by peerDependencyRules.ignoreMissing under conflicts or intersections #​8295.

Output and messages
  • The error for an incompatible pnpm-lock.yaml now reports the lockfileVersion the file was generated with and the lockfileVersion the current pnpm supports. The error also warns that recreating the lockfile with --force may break the application and suggests installing the pnpm version that generated the lockfile #​848.

  • When the registry stops sending data for longer than fetchTimeout, pnpm now reports that the metadata or tarball request timed out. Previously the error did not mention the timeout #​3646.

  • Resolution no longer logs an error when a package metadata request fails and resolution succeeds via cached metadata #​2522.

  • The ignored build scripts warning and the update notice are printed as plain lines when output is not a terminal, in CI, or with --reporter append-only. They were drawn inside a box that broke apart in CI logs #​9421.

  • pnpm run with --loglevel set to warn, error, or silent (or the same loglevel setting) no longer prints the $ <command> line before a script, nor the summary of the install that verifyDepsBeforeRun runs first. Both are info-level output #​8944.

  • pnpm add now warns when replacing an existing dependency with a specifier pointing to a different source #​14869.

  • pnpm update no longer warns "Skip adding ... to the default catalog" for a dependency that already uses catalog: #​13715.

  • pnpm remove --help no longer shows a [@<version>] suffix in its usage line. The command accepts package names only #​7751.

  • Bash completion now completes script names that contain a colon, such as pnpm run test:u to pnpm run test:unit #​5482.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.27.1: pnpm 11.27.1

Compare Source

Patch Changes

  • pn, pnpx, and pnx now run the pnpm installed alongside them. They used to look pnpm up on PATH. That failed when the directory holding them was not on PATH, and it silently handed the call to an unrelated pnpm when one came first there #​14803.

  • The @zkochan/cmd-shim package is now available as @pnpm/bins.cmd-shim.

  • pnpm cache list-registries now prints the registry URL, matching pnpm cache view. It printed https%3A+registry.npmjs.org before and prints https://registry.npmjs.org/ now #​15046.

  • pnpm deploy no longer installs the dependencies of the workspace root project into the deploy directory #​6437.

  • Install warnings no longer carry the text of a package's deprecation notice. The warning names the deprecated package and version, and the pnpm:deprecation event no longer carries the notice either. pnpm view still shows it on request.

    A deprecation warning now names the newest version of the package that is not deprecated, and says when reaching it means widening the range you declared:

    WARN  deprecated foo@1.0.0. 2.3.1 is not deprecated, outside the range you declared.
    

    pnpm works this out from the metadata it already fetched, so it costs no extra request. An install that reuses the lockfile without fetching metadata names no version.

    pnpm strips control characters from the package name and version in a deprecation warning, and from the notice pnpm outdated --long prints.

    The text sanitizer now also strips the Unicode line and paragraph separators U+2028 and U+2029.

  • pnpm exec <command> and pnpm <command> run from a subdirectory of a project now find the executables installed in the project's node_modules/.bin. The command still runs in the subdirectory. PNPM_PACKAGE_NAME names the project #​5068.

  • pnpm exec and pnpm dlx now wait for the command to finish shutting down after Ctrl+C. A signal sent to pnpm alone now reaches the command, the way it does with pnpm run. pnpm used to exit on the interrupt and terminate the command while it was still shutting down #​7374.

  • Warnings about ignored environment variables in project .npmrc credentials now link to the npmrc documentation pnpm/pnpm#15051.

  • pnpm audit --interactive --fix=update no longer opens a second prompt for selecting dependencies to update #​14927.

  • Fixed pnpm dedupe requiring a second pass after bumping a direct dependency in package.json pnpm/pnpm#14987.

  • pnpm deploy now writes plain versions for registry dependencies with peer dependencies in the deployed package.json. The deployed lockfile retains the resolved peer bindings. npm aliases keep their target package names #​14873.

  • pnpm publish now allows a detached Git HEAD in CI, including checkouts of release tags. The working tree must still be clean. Branch and remote-history checks still apply when HEAD is attached pnpm/pnpm#5894.

  • pnpm dlx and pnx now prompt to approve dependency build scripts in interactive terminals. Cached packages with pending builds also prompt for approval. Without an interactive terminal, use --allow-build to allow the required builds. Fixes pnpm/pnpm#14943.

  • pnpm install --force now removes obsolete dependency links inside virtual-store packages when their dependencies change. Invalid dependency names are ignored during obsolete-link cleanup #​15039.

  • pnpm add -g and pnpm update -g now ignore incomplete unrelated global package groups when every command from the replaced group is retained. Operations that could remove a global command still require complete ownership information.

  • Resolving a Node.js runtime now fails when unofficial-builds.nodejs.org cannot be reached. pnpm used to ignore that failure and leave the musl builds out of pnpm-lock.yaml. pnpm update then wrote a different lockfile on a machine whose network blocks the mirror pnpm/pnpm#14813.

  • pnpm now deduplicates a package whose child dependency resolved an optional peer in one workspace project but not in another. Two copies of next could appear when only some projects could reach styled-jsx's optional babel-plugin-macros peer #​14800.

  • Fixed shell completion of package scripts for pnpm run and pnpm run-script pnpm/pnpm#15034.

    Bash completion now preserves literal script names containing glob characters and shell punctuation in pnpm v11 and v12.

  • pnpm sbom now publishes a valid URL in the CycloneDX externalReferences[].url and the SPDX homepage. An npm shorthand such as vercel/ms or gitlab:group/subgroup/project is expanded to the git+https URL npm derives for it. An scp-style remote such as git@github.com:vercel/ms.git is expanded the same way. Any other URL is published in its normalized form, without embedded credentials. A value that names no repository, an email address for example, is left out. pnpm used to publish the raw value, so a shorthand produced a URL that consumers such as Dependency-Track reject pnpm/pnpm#14773.

  • pnpm setup now describes the displayed configuration changes as "the following configuration changes."

  • pnpm --version now reports why the pnpm version a project pins cannot be installed or recorded, then prints the version of the running CLI. It used to fail, which made the command unusable where the filesystem is read-only. pnpm --version also honors --store-dir and its --store alias now #​14831.

  • pnpm install --force now reinstalls dependencies when the manifest and lockfile are unchanged. It previously reported "Already up to date" without reinstalling. Files changed in node_modules are restored when the store content is intact. Combining --force with --frozen-store now reports a configuration conflict on repeat installs #​919.

  • pnpm install now installs git-hosted dependencies without preparing them when their builds are explicitly denied by allowBuilds. Dependencies that require preparation still need an explicit allow or deny decision pnpm/pnpm#10522.

  • pnpm runtime set and pnpm env use now use the pnpm version that started the command. They could run a different installed pnpm when the command was started through Corepack or another wrapper.

  • The install summary now names the version each dependency resolved to when node-linker is hoisted. It also lists what an install restores after node_modules is deleted, and both sides of a version change. The summary showed the range recorded in package.json, or nothing at all #​15161.

  • The @pnpm/npm-lifecycle package is now available as @pnpm/exec.npm-lifecycle.

  • Fixed minimumReleaseAge making pnpm download a package's full metadata again on every install. The cached copy carried a validator the registry could not match, so pnpm could never revalidate it pnpm/pnpm#15103.

  • pnpm now measures a pnpm.overrides entry written as a bare path, such as ./local-dep, from the directory holding pnpm-workspace.yaml. It used to be measured from each package the override rewrote, so the dependency linked to a directory that does not exist #​11131.

  • pnpm now preserves scalar YAML anchors and aliases when editing pnpm-workspace.yaml. Removing the entry that defines an anchor keeps surviving aliases valid. Entries updated to different values are written separately #​8245.

  • pnpm now preserves comments and existing key order when updating package.yaml. New keys are appended to their mapping pnpm/pnpm#2008.

  • pnpm install --prod no longer downloads the registry packages that only a devDependency reaches #​881.

  • pnpm update --global no longer reinstalls a global package when its dependency graph resolves to what is already installed. It reports Already up to date pnpm/pnpm#12002.

  • The minimumReleaseAge approval prompt now counts and displays each package version once pnpm/pnpm#15083.

  • pnpm run no longer sends a script a second SIGINT when Ctrl+C is pressed in a terminal. A script that shuts down on the first SIGINT and exits at once on a second used to die before its shutdown finished #​7374.

  • pnpm now reads a pnpm-workspace.yaml whose tasks section uses a setting only pnpm 12 acts on, such as concurrencyGroup. A task's unrecognized fields are ignored, unless the field only differs in case from concurrency or dependsOn, which pnpm reports as a typo.

    The warning about unrecognized top-level settings now names cargo, concurrencyGroups, and pipelines as pnpm 12 settings.

  • pnpm -r list --json now prints one JSON array. It printed a separate array for each project when sharedWorkspaceLockfile was false, so the output could not be parsed.

    pnpm -r list now reads each project's own modules directory when the projects keep their own lockfiles, so --long and --parseable report the packages that project installed #​15011.

  • A signal sent to pnpm while it runs without a terminal, as a container runtime or a service manager does, now reaches the script even when the shell running it stays the script's parent. pnpm then waits for the script to finish shutting down. Such a signal used to end the shell at once or stay with it, and the script was never told to stop #​7374.

  • Fixed minimumReleaseAge being skipped for packages served by a registry that returns the same ETag for abbreviated and full package metadata pnpm/pnpm#14925.

  • pnpm install now returns "Already up to date" in a workspace where dedupeDirectDeps left a project without a node_modules directory of its own. Such a project forced a full install on every run.

  • Installs in different projects that share a global virtual store no longer fail on Windows with Access is denied while repairing the same slot #​15114.

  • pnpm sbom now emits a license value as a CycloneDX expression only when it is a valid SPDX license expression. Anything else is emitted as a CycloneDX license name pnpm/pnpm#14786.

  • A dependency's own bins can no longer take over another package's bin shim. The POSIX shims pnpm generates used to look up their shell helpers on PATH, where a dependency's bins come first #​14837. Reinstalling replaces the shims already in your node_modules. On Cygwin, MSYS2, and WSL the shims still take their Windows path conversion from PATH, so a dependency can still redirect them there.

  • POSIX bin shims now convert a Windows-form path such as C:\node_modules\.bin\tsc correctly. The shim mangled the backslashes in such a path and could not reach the package it runs. Installing again replaces the shims already in node_modules #​14867.

  • pnpm pack now writes tarball entries grouped by file extension and file name, the order npm uses. Packages that ship many same-named files, such as template collections, pack much smaller #​14766.

  • A command run in a project that the workspace does not include now acts on that project alone. A project is outside the workspace when it has a manifest of its own and no pattern in the packages setting selects it, or when a ! pattern excludes it. A directory with no manifest of its own, such as a package's source directory, still belongs to the workspace. pnpm install in an excluded project used to install every project in the workspace #​3561.

  • POSIX bin shims now take cygpath and wslpath from the system default path on Cygwin, MSYS2, and WSL2. The shims looked both helpers up on PATH, where a dependency's own bins come first, so a dependency could redirect another package's shim. Installing again replaces the shims already in node_modules #​14866.

  • pnpm update and pnpm audit --fix=update no longer copy dependencies added by packageExtensions, a readPackage hook, or an override into package.json. Those dependencies keep the specifier the hook or override gives them. pnpm update --latest no longer resolves past that specifier. pnpm audit --fix=update now warns when one of them pins a vulnerable version. The warning points at pnpm audit --fix #​14928.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.27.0: pnpm 11.27

Compare Source

Minor Changes

  • nodeDownloadMirrors can now be set in the global config file (config.yaml) and through the PNPM_CONFIG_NODE_DOWNLOAD_MIRRORS environment variable, so a Node.js download mirror can be configured once for a machine instead of in every workspace #​12124, #​13611.

    PNPM_CONFIG_NODE_DOWNLOAD_MIRRORS='{"release":"https://npmmirror.com/mirrors/node/"}'
    
  • Added a new setting trustPolicyExcludePrune (default: false). When enabled, pnpm add, pnpm update, and pnpm remove prune the entries of trustPolicyExclude in pnpm-workspace.yaml that the freshly written lockfile no longer resolves: versions that are gone are dropped (an entry is removed once none of its versions remain), and entries for packages that are no longer in the lockfile are removed too. Name patterns (@scope/*) are always kept. The cleanup is skipped when the install's lockfile does not cover the whole workspace (sharedWorkspaceLockfile: false), since entries another project still needs would look stale.

Patch Changes

  • pnpm now reads the packageManager, devEngines.packageManager and runtime pins from the workspace root's package.json when lockfileDir is set. A project that moved its lockfile lost the pins it declared there #​14633.

  • Fixed pnpm add -g, pnpm update -g, and pnpm remove -g mutating global bins or install directories after only partially reading an installed package group. If any declared package manifest is missing, malformed, or unreadable, pnpm now fails before activation or removal and leaves the existing global installation intact pnpm/pnpm#13796.

  • fetch-timeout now limits how long a request may make no progress. The timer restarts on every chunk that arrives. A large download over a slow connection is no longer aborted while data is still coming in. A connection that stops delivering data still fails after fetch-timeout #​14604.

  • pnpm peers check no longer reports a peer dependency declared as workspace:^, workspace:~, or a bare workspace: as unmet. pnpm reported these as unmet whatever version the linked workspace project supplied #​14770.

  • A readPackage hook that edits its argument in place no longer changes what a later install in the same command resolves. A deprecated notice read from the lockfile no longer carries over to another install either #​13988.

  • pnpm install now auto-installs missing transitive peers when workspace projects share a dependency at different depths. This also removes incomplete duplicate peer contexts from the lockfile. Fixes pnpm/pnpm#14840.

  • GitHub Actions updates now stop if an action reference changes while its versions are being resolved. Unrelated workflow edits are preserved.

    GitHub Actions homepage links no longer expose server credentials. GitHub server URLs now require HTTPS, with HTTP allowed only for loopback hosts.

  • pnpm licenses list now reports the runtime downloaded through devEngines.runtime with onFail: "download". The command previously failed with ERR_PNPM_UNSUPPORTED_PACKAGE_TYPE #​14172.

  • pnpm no longer creates a project pnpm-lock.yaml when devEngines.packageManager.onFail is download and lockfile writing is turned off with lockfile: false or --no-lockfile. pnpm still switches to the pinned version #​14728.

  • A registry or @scope:registry set in an .npmrc now wins over the registry a pnpm login credential stored in the global config.yaml points at. Previously, after logging in to one registry, installs in a project whose .npmrc named a private registry went to the logged-in registry instead. They now go to the registry the .npmrc names #​14614.

  • A patch that gives a dependency a preinstall, install, or postinstall script, or a binding.gyp, now runs that build. pnpm asks for build approval first, so the package is listed under "Ignored build scripts" until it is allowed to build. pnpm 12 ran nothing, and pnpm 11 ran it without asking #​14648.

  • Registries that share a host but differ by URL path — one JFrog Artifactory, Nexus, AWS CodeArtifact or GitLab Packages instance serving several repositories — now get a metadata cache directory each. Previously they shared one, so resolving a package from one of them could answer with another's versions, integrity hashes and tarball URLs and fail with ERR_PNPM_TARBALL_URL_MISMATCH #​13558.

    The URL scheme is part of the cache directory name too, so an http registry can no longer hand its metadata — which can be rewritten in transit — to a resolution configured for https at the same host.

    The first install after upgrading refetches registry metadata once. The package store is untouched.

    pnpm cache view now labels each entry with the full registry URL. It printed registry.npmjs.org before and prints https://registry.npmjs.org/ now.

    pnpm cache list-registries and pnpm cache list print the new directory names. Scripts that parse either command need updating.

  • Updated the embedded Node.js release keys to the current canonical nodejs/release-keys list.

  • pnpm sbom now omits package author fields when the manifest author name is empty or contains only whitespace pnpm/pnpm#14685. In a filtered or split workspace run, only a project with no author field inherits the workspace root's author.

  • pnpm sbom --sbom-format spdx now writes creationInfo.created with whole seconds, such as 2026-09-08T10:38:21Z. The timestamp carried fractional seconds, which strict SPDX consumers rejected #​14684.

  • Windows filesystem operations now retry permission errors for up to one second. Permanent permission errors previously delayed failure by a minute. Sharing and lock violations retain their one-minute retry budget pnpm/pnpm#14682.

  • pnpm now writes node_modules/.package-map.json only when nodeExperimentalPackageMap is enabled. Nothing reads the file without that setting. An install that stops writing the map removes the one a previous install left.

  • pnpm now unpacks a downloaded runtime archive into a randomly named directory inside the store. It previously used a predictable path, where another user of a shared store could plant a symlink and redirect the write outside the store (GHSA-vwc7-r8mq-g2x9).

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.26.0: pnpm 11.26

Compare Source

Minor Changes

  • Catalogs can now resolve workspace dependencies through the workspace: protocol.

  • pnpm remove and pnpm update now accept --trust-lockfile, --no-trust-lockfile, --trust-policy, --trust-policy-exclude, and --trust-policy-ignore-after. pnpm remove checks the whole lockfile against the active policies unless --trust-lockfile is set.

  • Added pnpm change check for CI validation of package versions against the versioning.epics bands and versioning.fixed groups in pnpm-workspace.yaml.

Patch Changes

  • Fetch and tarball errors and retry logs now hide URL credentials, query strings, and fragments that could expose secrets.

  • Fixed a race during config dependency updates that could redirect a lockfile write through a symlink #​14322.

  • pnpm add --allow-build=!<pkg> now correctly denies builds, including in global installs. pnpm approve-builds <pkg> and pnpm approve-builds !<pkg> now save decisions even when the package is not awaiting approval, with a warning #​14067.

  • Fixed pnpm audit --fix failing without a value or when followed by another flag. pnpm audit --fix=override now respects saveExact and savePrefix when writing overrides #​13261, #​11523.

  • pnpm audit now excludes ignored advisories from vulnerability totals and severity counts, and reports them separately #​14535.

  • pnpm deploy no longer requires injectWorkspacePackages. If a workspace dependency's peer has multiple possible versions, deployment reports ERR_PNPM_DEPLOY_AMBIGUOUS_PEER with the conflicting versions. Pin the peer with overrides to deploy without injection #​9386.

  • Fixed concurrent installs sharing a store occasionally failing with an ENOENT error while importing a package file #​14353.

  • Fixed installation failures when a linked local dependency provides a peer dependency also provided by an ancestor, including with pnpm deploy --legacy.

  • pnpm install --node-linker=hoisted no longer downloads skipped optional dependencies when node_modules already exists #​14139.

  • Fixed pnpm install rejecting a symlinked lockfile when config dependencies are unchanged. Updates to config dependencies also preserve lockfiles with a byte order mark. Writes through symlinked lockfiles remain blocked #​14372.

  • pnpm install now relinks workspace packages when publishConfig.linkDirectory changes. Frozen installs require the lockfile to be regenerated #​14488.

  • Auto-installed optional peers now satisfy their declared range even when the workspace root uses a version outside that range #​13867.

  • Fixed global virtual store paths for dependency cycles to consistently account for the runtime engine when dependencies have allowed builds #​14341.

  • Standalone installations now preserve the bundled node-gyp files needed to build native dependencies.

  • Downloaded runtimes are now available to dependency lifecycle scripts during installation.

  • Node.js downloads from nodeDownloadMirrors now use URL-scoped npm credentials, including bearer tokens, basic auth, and tokenHelper #​14334.

  • Fixed globalDir and globalBinDir handling in global configuration and environment variables, including ~/ expansion. This fixes pnpm add -g failing after pnpm config set -g global-bin-dir #​14336.

  • The JavaScript pnpm can again switch to the project's pinned pnpm version on hosts without a matching native binary. If the requested version requires an unavailable native binary, the error now identifies the unsupported host #​13622.

  • Global pnpm config commands now skip project package manager version switching, allowing authentication to be configured before downloading the pinned version #​14463.

  • pnpm self-update, pnpm with, and automatic version switching no longer wait through registry retries when a configured registry has no signatures and registry.npmjs.org is unavailable #​14483.

  • Fixed argument forwarding on Windows with shellEmulator enabled. Trailing backslashes, line breaks, and literal shell expressions are preserved #​14548.

  • Relative scriptShell paths now resolve from the workspace root. Bare command names such as bash still use PATH #​14422.

  • pnpm import now preserves the project-local lockfile when lockfileDir points elsewhere and restores the destination lockfile on failure. Branch lockfile imports leave the shared lockfile unchanged #​14563.

  • catalogMode and --save-catalog no longer move local paths, tarballs, or workspace:<path> specifiers into catalogs #​14437.

  • --side-effects-cache, --no-side-effects-cache, and PNPM_CONFIG_SIDE_EFFECTS_CACHE now toggle only the local cache, preserving any remote cache configured in sideEffectsCache.

  • pnpm unpublish now handles registry two-factor authentication challenges through web authentication or a one-time password prompt #​14464.

  • pnpm outdated and pnpm update now follow GitHub Actions references using self-repository syntax, such as uses: $/.github/actions/setup.

  • pnpm remove now accepts --unsafe-perm.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

v11.25.0: pnpm 11.25

Compare Source

Minor Changes

  • Added an opt-in proof of concept that lets installs reuse a dependency's build output across machines, by publishing and restoring signed, organization-scoped artifacts through pnpr instead of running the lifecycle scripts locally.

    Configure it with the new remoteSideEffectsCache setting. A workspace names the eligible organization and packages; everything describing the act of signing — publish, keyId, builderId, trustedKeys, privateKey and the provenance fields — is refused in pnpm-workspace.yaml and read from the global config file or the environment instead.

  • Added macOS and Windows x64 and arm64 support to remote shared build artifacts pnpm/pnpm#13771.

  • Added the audit.ignorePrune setting. When set to true, pnpm audit --fix removes ignored GHSA entries that no longer appear in the audit report.

  • Generalized the experimental shared-artifact protocol so candidates and signed payloads identify a discriminated subject. Dependency side effects use package and source-integrity subjects, while workspace tasks use project and task subjects.

    This changes shared-artifact request bodies and signed payloads. A pnpr server and its clients have to be on matching versions.

  • pnpm init now pins the latest pnpm version, instead of the version of pnpm that ran the command. A project scaffolded by an outdated pnpm therefore no longer inherits that staleness through its own devEngines.packageManager / packageManager pin #​7490.

    The version is read from the latest tag on the package-manager registries. When that lookup cannot answer — no network, an unreachable or slow registry, offline, or a latest that the minimumReleaseAge / trustPolicy settings reject — pnpm init pins the running version as before, and never fails or hangs on the lookup. A latest that is older than the running pnpm is never pinned either.

  • A scope set in a project's pnpm-workspace.yaml is now ignored, with a warning naming where to set it instead. pnpm login records the scope as a @scope:registry route in the machine-global auth.ini, which outranks ~/.npmrc in every project — so a repository-committed file could redirect a scope such as @acme for all of a user's other projects after one routine login. Use --scope, the PNPM_CONFIG_SCOPE environment variable, or the global config file instead #​13557.

  • Verified remote build artifacts are persisted in the shared store with their signed origin metadata. Later installs reverify the artifact against current trust, policy, platform, and source before reuse, while invalid remote variants are quarantined per channel (pnpm/pnpm#13771).

  • Persist completed recursive tasks so --resume-from skips exactly the work that passed during a matching interrupted or failed pnpm -r run / pnpm -r exec invocation. When no compatible state exists, pnpm retains its graph-based resume behavior.

  • Allowed pnpm update --patches to refresh registry revisions through a configured pnpr server while retaining locked package versions.

  • Added explicit registry revision selection with <version>+rN and pnpm update --patches for refreshing revision artifacts without changing package versions. Registry-backed lockfile policy checks recognize historical revisions, and pnpr now preserves safe revision histories from upstream registries.

  • Workspace install, rebuild, pack, publish, stage, and lifecycle work now starts as soon as its dependencies finish instead of waiting for an unrelated topological group.

  • pnpm stage approve now approves several staged packages at once. Run it without a stage id to pick from the staged versions interactively, or pass a list of stage ids. The whole batch is approved with a single one-time password, and pnpm asks for a new one only once the registry stops accepting it. Inside a workspace, the selected packages are approved in dependency order, and a package whose workspace dependency could not be approved is skipped instead of being published against a dependency that never reached the registry.

  • Added per-task concurrency limits to workspace task orchestration. Set tasks.<name>.concurrency in pnpm-workspace.yaml to limit how many instances of that task may run across workspace projects at once:

    tasks:
      build:
        concurrency: 2
    
  • Added support for registry replacement tarballs using standard integrity values, explicit revision fields, registry routing from the registries setting, non-redirecting integrity-addressed URLs, canonical safe-integer revision numbers, and pnpr proxying for immutable upstream revision artifacts.

  • sideEffectsCache now declares the whole of how a package's build output is reused — whether one is restored, whether one is saved, and the remote tier that shares it between machines:

    sideEffectsCache:
      read: true
      write: true
      remote:
        org: acme
        packages: ['native-addon']
    

    sideEffectsCache: true, sideEffectsCacheReadonly, remoteSideEffectsCache, and its organization field all keep working. Where a field is set under both spellings the one above wins; where it is set under only one, it is kept.

    Two behaviors change, both bringing this CLI in line with what the Rust one already did: sideEffectsCacheReadonly: true now blocks writing to the cache, and setting it alongside sideEffectsCache: false gives a read-only view rather than switching the cache off entirely. A cache can also be declared write-only now, to populate one the run does not read.

  • Workspace task orchestration (pnpm/rfcs#23). pnpm -r run and pnpm -r exec now schedule per task instead of in topological chunks: a task starts as soon as the tasks it depends on have finished, so a project no longer waits for unrelated projects that happen to share its chunk.

    A new tasks section in pnpm-workspace.yaml declares what a task depends on, using the ^ convention:

    tasks:
      build:
        dependsOn: ['^build']
      test:
        dependsOn: ['build']
      lint: {}
    

    ^name means the named task in each of the project's workspace dependencies; a bare name means the task in the same project; an entry with no dependsOn declares an empty dependency list. A task with no entry behaves as dependsOn: ['^<its own name>'], which is exactly what the previous chunked ordering implied — an unconfigured workspace gets the scheduler improvement and nothing else changes meaning. A project without the script is reported skipped and passes its edges through to its own dependencies, so a scriptless package does not sever a chain.

    Also part of this change:

    • A dependency cycle among the tasks of a run is now an error naming the participating tasks (ERR_PNPM_TASK_CYCLE) instead of silently running in an arbitrary order. Setting ignoreWorkspaceCycles: true downgrades the error to a warning: the cycle's tasks run in an arbitrary order relative to each other.
    • --resume-from now skips exactly the transitive dependencies of the anchor package; work unrelated to the anchor still runs.
    • Under --no-bail, tasks whose dependencies failed are reported as skipped, not failed, and do not add to the exit code.
    • With --bail (the default), the first failure still ends the run at once and nothing new is dispatched — including scripts already queued behind the concurrency limit.
    • pnpm -r run --dry-run <script> prints the task graph that would execute without running anything (including skipping the verifyDepsBeforeRun check); --json emits the tasks and their resolved dependency edges.
    • Output is inherited rather than piped only when at most one script can ever be in flight (--workspace-concurrency=1, or the graph forces the scripts to run one after another).

Patch Changes

  • An _auth entry in the global config file no longer decides which registry packages come from when something else says. A registry or registries declared in pnpm-workspace.yaml or the global config now wins over the route inferred from a stored credential, which still applies where nothing else declares one. The pnpm_config__auth environment variable is unchanged: it stays the way to point a CI runner at a mandated proxy, and still overrides what a repository declares.

  • Prevent installs through a symlinked node_modules directory from rewriting the target checkout pnpm/pnpm#14286.

  • Treat empty scripts selected by a regular expression as missing before running dependent tasks.

  • The options type of the fetch command now declares allowBuilds, a setting its handler already forwarded to the installer. Type-level only — what pnpm fetch does is unchanged.

  • Filter hidden scripts matched by a regular expression during recursive runs when a visible script also matches.

  • Fixed automatically switched pnpm versions forcing all descendant pnpm processes to use the same version pnpm/pnpm#14309.

  • Fixed ERR_PNPM_UNUSED_PATCH validation during incremental installs pnpm/pnpm#13692.

  • Fixed pnpm deploy --prod failing when an excluded dev dependency was also declared as an optional peer dependency pnpm/pnpm#14302.

  • pnpm update -g no longer downgrades a global package. --latest resolves the latest dist-tag, which can point at an older release than the one installed — after pnpm add -g <pkg>@next, for instance #​14270.

    pnpm update -g also no longer changes the pnpm version. pnpm's own global install belongs to pnpm self-update #​14270.

  • Copying a built package to its other hoisted locations no longer replaces the destination directory. With nodeLinker: hoisted, that replacement deleted the dependencies nested inside the destination's node_modules, and made concurrent copies of the same build chunk fail with ERR_PNPM_ENOENT: no such file or directory, rename '.../node_modules/_tmp_...' #​12880.

  • pnpm update no longer replaces the specifier a project declares for a dependency that is also listed in overrides. A catalog: reference stays a catalog: reference, and a declared range stays as written, instead of being rewritten to the version the override resolved to #​12115.

  • pnpm update no longer moves the range a project declares for a dependency that overrides also lists, even when the override repeats that range verbatim. Previously the updated package.json disagreed with the lockfile, so the next pnpm install --frozen-lockfile failed with a specifier mismatch #​14224.

  • Make pnpm add --lockfile-only skip dependency linking pnpm/pnpm#14286.

  • --production is accepted again as an alias of --prod on install, fetch, prune, update, list, why, and sbom, and the install that verifyDepsBeforeRun reproduces is now spelled with --prod. pnpm run no longer aborts with "unexpected argument '--production' found" after a production-only install #​14147.

  • The progress output no longer overwrites the lines above it once it grows taller than the terminal window #​14270.

  • Restoring a dependency's build from the remote side-effects cache no longer downloads files the store already holds.

  • Forward patchedDependencies hashes and packageExtensions to pnpr so server-side resolution preserves patches and package extensions in the lockfile and installed packages.

  • Published the workspace task graph and scheduler as @pnpm/workspace.task-scheduler so other workspace commands can use the same dependency-aware scheduling as recursive run and exec.

  • The environment variables for the remote side-effects cache are named for the setting they configure: PNPM_SIDE_EFFECTS_CACHE_REMOTE_KEY_ID, ..._BUILDER_ID, ..._IMAGE_DIGEST, ..._ARCHITECTURE_BASELINE, ..._PRIVATE_KEY, ..._BUILD_ENV, ..._TRUSTED_KEYS and ..._PUBLISH. The PNPM_REMOTE_SIDE_EFFECTS_CACHE_* names keep working, and the new one wins when both are set.

  • A devEngines.packageManager range pin on pnpm is now recorded in pnpm-lock.yaml's packageManagerDependencies when the running pnpm already satisfies it, using the running version and keeping the range as the recorded specifier. Previously only an exact pin — or a range resolved on the way through a version switch — reached the lockfile, so a range pin written by hand (or by any tool other than pnpm add / pnpm self-update) left the project without the shared resolution the pin exists to provide.

  • Fixed recursive run cleanup on Windows when a lifecycle script fails while another script's process tree is still running.

  • The update notification now suggests pnpm self-update when PNPM_HOME manages the pnpm in use, and the standalone install script otherwise — under Corepack, or when another package manager installed pnpm. pnpm self-update under Corepack names the standalone install script too.

  • Enforce allowBuilds when a prepared git dependency is reused from the shared store, and use the lockfile's canonical git resolution ID in approval suggestions.

  • Topologically sorting workspace projects now runs in linear time, fixing installs and lockfile updates that stalled for seconds on workspaces with thousands of projects forming deep dependency chains #​14149, #​14151.

Platinum Sponsors

Bit OpenAI Notion

Gold Sponsors

Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx Latitude

v11.24.0: pnpm 11.24

Compare Source

Minor Changes
Patch Changes
  • Fixed pnpm v11 incorrectly reporting confirmModulesPurge as unrecognized when set in pnpm-workspace.yaml. The Rust CLI now identifies the unsupported option as a pnpm v11 setting instead of suggesting an unrelated setting.

  • pnpm install --frozen-lockfile no longer fails with ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE when the pinned pnpm version recorded in pnpm-lock.yaml has to be re-resolved before it can be installed. It runs the pnpm version the lockfile pins and leaves the lockfile unchanged #​14124.

  • Under nodeLinker: hoisted, peer-resolution variants of an injected directory dependency (a file: snapshot) are materialized as separate copies again instead of collapsing onto the first-seen variant. Each copy keeps its own peer-resolved dependency set, so a project pinning one peer version no longer resolves another project's variant — Bit root components with conflicting peers across injected copies rely on this.

  • Fixed pnpm install --merge-git-branch-lockfiles --frozen-lockfile failing with ERR_PNPM_OUTDATED_LOCKFILE when a branch lockfile predates the removal of a dependency, or its move to another dependency group #​13966. A dependency that no project declares anymore is no longer reinstated by the merge, and the packages it was the only path to are dropped with it.

  • Batch workspace publishing accepts a shared scope-specific credential, rejects mismatched credentials for a registry before publishing, and runs the publish and postpublish scripts after each completed registry group pnpm/pnpm#14101.

  • The Rust CLI now honors five settings it recognized but ignored: updateNotifier, legacyDirFiltering, initAuthorName / initAuthorEmail / initAuthorUrl, initLicense, and initVersion. pnpm install and pnpm add check once a day for a newer pnpm and print how to get it (turn it off with updateNotifier: false); a {<dir>} filter selector can go back to matching the subtree below the directory with legacyDirFiltering: true; and pnpm init writes the configured author, license, and version into the package.json it scaffolds. PNPM_CONFIG_INIT_VERSION is now read as well.

    maxsockets, npm's spelling of maxSockets, is no longer ignored: both spellings are read from pnpm-workspace.yaml, the global config file, the environment, and the command line, in that increasing order of precedence — a value passed on the command line now wins even when the two sides spelled the setting differently.

    A lastUpdateCheck timestamp dated in the future — after a clock change, a restored snapshot, or a hand-edited state file — no longer silences the update check until that time comes around.

    legacyDirFiltering no longer reaches the workspace-root selectors pnpm generates for itself: the !{<workspace-root>} exclusion a recursive run / exec / add / test appends, and the {<workspace-root>} inclusion --workspace-root appends. Read as subtree matches they named every project below the root, so a recursive command under the setting selected nothing at all, and --workspace-root pulled in every project below the root instead of the root alone #​14101.

  • pnpm install --frozen-lockfile no longer fails when pnpm-lock.yaml records the pinned pnpm version alongside an engine package the running pnpm does not install it from. An entry pinning another version is still refused, and a plain install rewrites the block #​14124.

v11.23.0: pnpm 11.23

Compare Source

Minor Changes

  • pnpm config get and pnpm config list now show the settings pnpm acts on under their documented names:

    • registries shows the registries pnpm resolves from, merged across every source (.npmrc, pnpm-workspace.yaml, the global config, CLI flags), in the shape the setting is written in: keyed by registry URL, with the default registry declared as the bare @ scope. Built-in routes are included — the @jsr scope and the npmjs and gh prefixes — unless pointed elsewhere. Previously pnpm config get registries printed undefined.
    • update and audit show the effective sections, whichever spelling set them. The deprecated internal spellings (updateConfig, auditConfig, auditLevel) are no longer listed.
    • catalogs shows the complete resolved catalog set — the singular catalog block is its default entry — whichever spelling declared it.
    • The registry and @scope:registry entries show the merged routes rather than raw .npmrc values, so they always agree with the registries view.
  • Settings that no supported pnpm version recognizes get their own warning. A key in the global config file that this version of pnpm does not read is no longer reported with advice to move it to a project-level pnpm-workspace.yaml (where it would be ignored too); the warning now says the setting is not recognized by this version of pnpm, names the pnpm version that does read it when there is one (for example, globalShims is a pnpm v12 setting), and suggests the closest real setting name when the key looks like a typo. Unrecognized and non-camelCase keys in a project's pnpm-workspace.yaml, previously ignored silently, are now reported the same way. pnpm config get <key> and pnpm get <key> no longer print config-load warnings, so a script capturing the value gets the value alone.

  • The importPackage pnpmfile hook is deprecated. pnpm now prints a warning when a pnpmfile defines it, and the hook will be removed in the next major version. It also opts the installation out of the parallel package importer, making installation slower. If you rely on this hook, comment on #​14101.

  • node_modules/.modules.yaml no longer records the registries an install resolved from, and the recorded copy is dropped from the file on the first install that rewrites it.

    It dated from the lockfile format that spelled a dependency's path relative to its registry, where reading an installed tree meant knowing the registries it was installed with. Dependency paths have not carried a registry for several major versions, and the recorded copy outlived its use: pnpm list, pnpm why, and single-project installs preferred it over the project's own configuration, so a project whose registry had changed since its last install was still read through the old one.

    They now use the configured registries, like every other command already did.

  • When enableGlobalVirtualStore is on, every process pnpm spawns for the project (pnpm run, pnpm exec, lifecycle scripts) now receives a NODE_PATH pointing at the project's hoisted node_modules, plus a NODE_OPTIONS --import flag that registers a resolve hook restoring NODE_PATH lookups for ESM imports. Dependencies that import undeclared ("phantom") packages keep resolving under the global virtual store — for both CommonJS and ESM — without installing the @pnpm/plugin-esm-node-path config dependency pnpm/pnpm#9618. Tools run by pnpm dlx resolve such dependencies too: the JS CLI passes them the same environment, while the Rust CLI's dlx cache is self-contained, so its layout already exposes them.

  • A registry can now declare that its abbreviated metadata carries the time field, so resolutionMode: time-based reads the full metadata document only from the registries that need it:

    resolutionMode: time-based
    registries:
      https://npm.internal.example/:
        supportsTimeField: true
    

    registry.npmjs.org omits time from abbreviated metadata, so a time-based resolution has to fall back to the much larger full document. That fallback used to be all-or-nothing: registrySupportsTimeField answered for every registry at once, so a project resolving from both the public registry and a Verdaccio instance either paid for full metadata everywhere or claimed a time field npmjs does not serve. The answer is now per registry, and registrySupportsTimeField remains the answer for every registry that does not declare one.

    The declaration is also sent to a pnpr server, which applies it to the resolution it runs on the client's behalf.

  • A pnpr resolve request now carries the client's registries the way the registries setting declares them — keyed by URL, with the scopes routed to each, the bare-specifier prefix each answers to, and each one's serverType — in place of the prefix map it used to send.

    The server routes them through the same inversion the config reader runs, so a pnpr-served install resolves a scoped dependency from the registry that scope is routed to, which it previously could not: only the default registry and the prefix-addressed ones reached the server. A declared serverType reaches it too, so the tarball URLs pnpr omits from the lockfile match the ones the client reconstructs.

    Built-in scope routes the project has not pointed elsewhere are not declared, so a pnpr server's allowlist is not asked about npm.jsr.io on requests that resolve no JSR package.

    A registry a request only declares is no longer refused up front for being off the server's allowlist — a client describes its whole configuration, including scopes a given resolve never reaches, so a stray @scope:registry in a developer's ~/.npmrc no longer fails every install against a pnpr server that does not serve it. The boundary moves to the fetch itself: an origin the resolve does reach is refused before the request leaves the server, with the same message.

    This changes the resolve and verify-lockfile request bodies. A pnpr server and its clients have to be on matching versions; the protocol is still experimental and unversioned.

  • The registries setting now declares a registry once, keyed by its URL, with everything about that registry in the entry: how it lays out tarball URLs, the scopes routed to it, and the bare-specifier prefix it answers to.

    registries:
      https://artifactory.example.com/artifactory/api/npm/npm-virtual/:
        serverType: artifactory
        scopes: ['@acme', '@acme-internal']
        prefix: work
    
    • serverType tells pnpm how the registry lays out its tarball URLs, which decides whether a URL can be omitted from pnpm-lock.yaml:
      • undeclared (the default) — strict. Only the exact canonical URL is treated as reconstructible.
      • npm — the registry behaves like registry.npmjs.org, which also serves a scoped package from its percent-encoded path. Declare this for a faithful mirror or caching proxy of the public registry so its tarball URLs can be omitted too.
      • artifactory — JFrog Artifactory repeats the scope in a scoped package's tarball filename (@acme/widget/-/@acme/widget-1.0.0.tgz) where the npm registry strips it (@acme/widget/-/widget-1.0.0.tgz). Declaring it lets pnpm rebuild that URL, so it is omitted from pnpm-lock.yaml instead of being written out for every scoped package pnpm/get-npm-tarball-url#16.
    • scopes lists the @-prefixed scopes that resolve from this registry. A bare '@' is the scope-less default registry, the one the registry setting names.
    • prefix is the alias a dependency addresses this registry by, as in "foo": "work:^1.0.0".

    The layout is never inferred from the registry URL, so nothing changes unless you declare it; registry.npmjs.org continues to behave as npm without being declared. Because the lockfile depends on serverType, it is read from pnpm-workspace.yaml only — a serverType in the global config.yaml is ignored, so one developer's machine cannot shape a lockfile their collaborators read back with a different layout. Credentials are rejected in this setting, in a key as well as in a field, and still belong in .npmrc. An entry that routes nothing to itself and matches no configured registry is reported as a warning rather than silently ignored.

Migrating

The older registries shape, a map of <scope>: <url> strings, still works and needs no change:

registries:
  '@acme': https://npm.acme.example/

namedRegistries is deprecated in favor of the prefix field, and is still read for prefixes registries does not declare.

toLockfileResolution and isCanonicalRegistryTarballUrl now take their registry and layout as an options object rather than positional arguments, so @pnpm/lockfile.utils and @pnpm/resolving.tarball-url get a major bump.

  • An install that had to re-hash store files to verify them now reports it. If that cost more than a second, it says how long — The integrity of N files was checked in 2.5s. — and if it was quick but covered more than a thousand files, it names the cause instead: their timestamps changed since the store recorded them, which a backup tool, an antivirus scan or a copied store can do.

  • Added virtualStoreType, which names where the virtual store lives — one store per machine, or one per project:

    virtualStoreType: global   # or: project
    

    It is the canonical spelling of enableGlobalVirtualStore, which keeps working. When a project sets both, virtualStoreType wins. It can also be set through PNPM_CONFIG_VIRTUAL_STORE_TYPE and read back with pnpm config get virtualStoreType. The default is unchanged — project, so the shared store stays opt-in.

    The setting is independent of nodeLinker. isolated and pnp both work with either store type, and hoisted writes no virtual store at all, so it is unaffected.

Patch Changes

  • pnpm add --allow-build now adds to the allowBuilds entries already in pnpm-workspace.yaml instead of replacing them #​13872.

  • Kept pending build approvals available after removing an unrelated dependency.

  • pnpm approve-builds now removes onlyBuiltDependencies, onlyBuiltDependenciesFile, neverBuiltDependencies, and ignoredBuiltDependencies from pnpm-workspace.yaml when it writes allowBuilds. Those settings were replaced by allowBuilds in pnpm 11 and silently ignored since, so a workspace migrated from pnpm 10 kept them around looking active.

  • pnpm audit no longer reports a patched version that was never published or is deprecated. The inferred patched range (e.g. >=4.17.24 from <=4.17.23) is now checked against the registry packument, and the report is corrected to the lowest non-deprecated published version that satisfies it (e.g. >=4.18.1 when 4.17.24 does not exist and 4.18.0 is deprecated). When no published version satisfies the range, the report shows Patched versions: None. This also prevents pnpm audit --fix from adding overrides or minimumReleaseAgeExclude entries for patches that do not exist #​13824.

    pnpm audit --fix and pnpm audit --fix update no longer add a minimumReleaseAgeExclude entry when the registry packument shows that the minimum patched version was never published. Previously such entries were written for versions that do not exist, which would have let a later publish of that version bypass the minimumReleaseAge gate #​11563.

    The --json output of pnpm audit now returns patched_versions: null for advisories whose inferred patch is not available (never published, skipped, yanked, or deprecated), making it easier for tooling to distinguish "no fix available" from "fix available at version X".

  • Fixed pnpm patch-commit in project and edit paths containing non-ASCII characters.

  • The package and bump pickers of pnpm change now size their page from the terminal height instead of always showing 7 rows. They fall back to 7 rows when the terminal height is unknown pnpm/pnpm#13815.

  • Canceling a pnpm change prompt with Ctrl-c no longer prints a stack trace. It reports Change canceled and exits with a success status, like the other interactive commands #​13814.

  • Re-fetch full registry metadata when minimumReleaseAge is enabled and an abbreviated packument's time map omits timestamps for some versions. This prevents mature versions from being filtered out and resolution from falling back to the lowest matching version pnpm/pnpm#13741.

  • A config dependency carrying an inline integrity (the <version>+<integrity> form, or the object form without a tarball) now takes its tarball URL from the registry's packument instead of deriving it from the registry URL, so migrating one costs an extra metadata request. On a registry that serves tarballs from a path pnpm cannot derive, GitLab's group endpoint for one, installing such a config dependency failed with a 404 while the same package installed fine as a regular dependency #​13765.

  • Fixed PNPM_CONFIG_NODE_VERSION being ignored when setting the Node.js version used for compatibility checks.

  • A custom fetcher can no longer replace the archive integrity that pnpm-lock.yaml pins: the locked value is restored after a canFetch or fetch hook rewrites the resolution, and delegating a locked archive to a directory or git source now fails instead of installing unverified content.

    The Rust CLI now also loads the pnpmfiles named by the pnpmfile setting (a single path or an ordered list), and hands custom fetchers native localTarball and remoteTarball callbacks — including on a fresh install that has to compute a missing tarball integrity, which is then reused by later offline installs. File maps a fetcher returns are accepted only when they match what those native callbacks extracted.

  • Fixed an issue where running pnpm dedupe --check in projects with nodeLinker: hoisted would cause dependencies to be moved out of node_modules into node_modules/.ignored.

  • pnpm deploy --prod and pnpm deploy --no-optional no longer list the excluded dependency groups in the deployed package.json and pnpm-lock.yaml. The deployed lockfile referenced packages that the deploy left out of its graph, so installing in the deploy directory afterwards created dangling symlinks #​13623.

  • Don't treat files like license16.json as a package license when deciding if the workspace LICENSE file should be included in the packed package.

  • pnpm exec --recursive --no-reporter-hide-prefix no longer prints a blank prefixed line after each chunk of a command's output, and no longer splits a line in two when it straddles a chunk boundary.

  • Fixed 404 errors when installing from a registry that serves scoped packages only from a percent-encoded path, such as GitHub Enterprise Server. Outside registry.npmjs.org, a tarball URL that encodes the scope separator as %2f or %2F is no longer mistaken for one that pnpm can rebuild from the package name, version, and registry, so it is kept in pnpm-lock.yaml and requested verbatim on the next install #​13534.

  • Fixed trustPolicyExclude and minimumReleaseAgeExclude being ignored when set to a single string instead of a list. The value was read one character at a time, so the exclusion never matched the package it named — and a * anywhere in it matched every package, silently switching the policy off.

  • pnpm init now pins the exact pnpm version instead of a ^ range, and records it in the packageManager field alongside devEngines.packageManager. Corepack reads only packageManager and accepts nothing but an exact version, so it rejected the generated package.json with "expected a semver version" pnpm/pnpm#13969. A package created inside an existing workspace is still left unpinned — it follows the pin at the workspace root — and --no-init-package-manager still scaffolds a manifest without any pin. In pnpm 12, pnpm init also honors initType and its --init-type flag, so the manifest it writes is the same one pnpm 11 writes.

  • Fixed an issue where package overrides were written into the metadata cache, causing removed overrides to keep applying on subsequent installs pnpm/pnpm#13918.

  • On Windows, upgrading pnpm no longer leaves a stale pnpm.ps1 behind. PowerShell resolves pnpm.ps1 ahead of pnpm.cmd, so a shim written by an older installation kept running the previous version. Linking the pnpm CLI's bins now deletes it #​13919.

  • Fixed an inconsistency where minimumReleaseAgeExclude (and trustPolicyExclude) wildcard/bare-name rules behaved differently in the evaluator and normalizer. A bare rule now consistently evaluates as matching every version, preventing unexpected behavior and silent widening of version policy exemptions when pnpm rewrites the workspace manifest pnpm/pnpm#13725.

  • A frozen install no longer rewrites the packageManagerDependencies block of pnpm-lock.yaml. When the pnpm version pinned by devEngines.packageManager (or by packageManager) is missing from the lockfile or no longer matches it, --frozen-lockfile now fails with ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE instead of resolving the version and saving it, so a manifest whose pin was bumped without regenerating the lockfile can no longer pass CI #​14009.

  • A git dependency installed over HTTPS from a hosted repository now keeps its branch, tag, or version range in the specifier recorded in package.json. It was written back without one, so the next pnpm update moved the dependency to the repository's default branch #​13999.

  • Fixed pnpm update --global --latest failing with a 404 error when a globally installed package was not added from the registry by name. Packages installed from a local path (link:/file:), a git repository, a tarball URL, an npm: alias, or a named registry now keep their spec during a global update instead of being looked up by name in the default registry. See #​12854.

  • Fix recursive pnpm update <name>@<version> so an exact pinned update stays scoped to the requested version line: copies of the same package on another major line — or, for a 0.x request, another minor line — keep their locked resolution instead of being re-resolved along with the target.

  • Under nodeLinker: hoisted, a dependency declared against a peer-resolution variant of a package version is no longer dropped from the installed layout. All variants of a version share one hoisted copy, and edges pointing at any of them now resolve to it, so the depending project keeps the package in its .package-map.json and the depending package keeps it in its node_modules/.bin.

  • Fixed pnpm install --merge-git-branch-lockfiles deleting the per-branch lockfiles when the lockfile setting is false. Such an install never reads them, so it has nothing to merge them into and now leaves them alone.

  • Fixed pnpm install sometimes not exiting after printing Done in Xs #​12297.

  • Fixed pnpm failing to read .modules.yaml files containing long dependency paths #​13875. The manifest is now parsed as JSON (the format pnpm writes it in), falling back to the YAML parser only for manifests written by old pnpm versions.

  • With preferSymlinkedExecutables, NODE_PATH again points at the virtual store of the workspace root when pnpm is run from inside a workspace package, so scripts can resolve dependencies that live only in the hoisted store #​13912.

  • Reduced registry metadata requests during dependency resolution by reusing cached metadata when lockfile preferences prove that no uncached version can win pnpm/pnpm#13976.

  • pnpm pkg get and pnpm pkg set now accept hyphens inside a dot-notation property path, so pnpm pkg get dependencies.some-package-name reads the key instead of failing with ERR_PNPM_UNEXPECTED_TOKEN_IN_PROPERTY_PATH. The bracketed and quoted forms already worked and are unchanged.

  • A resolve request now carries the client's resolutionMode, so an install delegated to a pnpr server picks versions the way the client would. time-based and lowest-direct reached the server as nothing at all, leaving it on its highest default: the returned lockfile pinned the highest satisfying version of every dependency, and the setting appeared to be ignored.

    This adds a field to the resolve request body. A server older than its client ignores it and keeps resolving highest; the protocol is still experimental and unversioned.

  • Fixed pnpm installs using pnpr to honor the client's autoInstallPeers, dedupePeers, and excludeLinksFromLockfile settings pnpm/pnpm#13389.

  • pnpm remove now prunes undecided entries ("set this to true or false") from allowBuilds in pnpm-workspace.yaml when sharedWorkspaceLockfile: true and the corresponding packages are removed pnpm/pnpm#13892.

  • Fixed workspace discovery for pnpm-workspace.yaml files without a packages field so commands only consider the workspace root instead of recursively scanning nested projects #​14047.

  • A runtime installed through devEngines.runtime now matches the host when supportedArchitectures lists several platforms. Listing os: [darwin, linux] and cpu: [x64, arm64] used to install the runtime built for the first entry of each list, so a machine running Linux on arm64 got a macOS x64 Node.js that could not execute #​13898.

  • pnpm sbom now fails with ERR_PNPM_SBOM_MISSING_IMPORTERS when pnpm-lock.yaml has no entry for a selected project, instead of writing an SBOM that under-reports that project's dependencies. Previously this crashed with Cannot read properties of undefined (reading 'devDependencies').

  • pnpm self-update now rewrites a simple devEngines.packageManager.version range (^/~) to the newly installed version, keeping the operator — matching how pnpm update and pnpm runtime set rewrite ranges. Complex ranges such as >=8.0.0 that the new version satisfies are still left unchanged #​13935.

  • pnpm self-update <tag> no longer downgrades when the dist-tag points at the pnpm version already running and that version is younger than minimumReleaseAge. The maturity cutoff moved the tag back to the previous mature release, so pnpm self-update next-12 on v12.0.0-rc.4 switched to v12.0.0-rc.3.

  • pnpm set-script now updates package.json instead of failing with ERR_PNPM_NOT_IMPLEMENTED pnpm/pnpm#13956.

  • pnpm update now preserves the existing range operator when updating a prerelease dependency. See #​7002.

  • Installs are faster in workspaces that declare inter-workspace dependencies with plain ranges ("*", "^1.2.3") rather than the workspace: protocol. With preferWorkspacePackages enabled, linking such a dependency no longer makes a registry request that cannot change the outcome — and workspace packages that were never published no longer cost a 404 on every install.

  • Added fetchWarnTimeoutMs and fetchMinSpeedKiBps to the Rust pnpm CLI and its N-API bindings. Slow registry metadata requests and tarball downloads now emit pnpm-compatible warnings without exposing URL credentials, query parameters, fragments, or control characters pnpm/pnpm#12042.

  • An override change is now absorbed by the fast lockfile update even when another, unchanged override uses the catalog: protocol. Previously any catalog:-valued override forced a full re-resolution whenever the override list changed, which could move unrelated packages in the lockfile (for example after pnpm audit --fix added an override).

  • Packed workspace package manifests now preserve dependency order, making repeated pnpm pack output deterministic #​10167.

  • pnpm update <name>@<version> now fails with ERR_PNPM_UPDATE_VERSION_ON_INDIRECT_DEP when the package is not a direct dependency of any selected project, instead of quietly updating it to whatever a fresh install would resolve. There is nowhere to record the version in that case, so the request cannot be honored, and the error points at the overrides entry that does pin a transitive dependency. Ranges and tags are unaffected, and a package that any selected project declares directly still takes its version as before.

  • trustPolicy: no-downgrade no longer aborts the install with ERR_PNPM_MISSING_TIME on registries that serve no per-version time field when minimumReleaseAgeIgnoreMissingTime is set. The trust check reads the same publish dates the minimumReleaseAge check does, so it now honors the same opt-in and skips the affected package with a warning #​12446.

    minimumReleaseAgeIgnoreMissingTime no longer lets a lockfile entry the registry does not list pass the minimumReleaseAge check during lockfile verification. The opt-in covers a registry that cannot date its releases; a packument that does date every version it lists is saying it never published this one, which stays a hard failure.

    The missing-time warning now names the check it is reporting on, so a package whose minimumReleaseAge and trustPolicy checks are both skipped warns about both instead of only the first.

  • pnpm update <pkg>@<version> now updates only the selected packages and leaves unrelated dependencies unchanged. A selector that renames the package it installs — pnpm update <alias>@npm:<pkg>@<version> or the jsr: equivalent — now targets the package the alias installs rather than the alias.

  • Fixed verifyDepsBeforeRun being ignored when set to install, warn, error, or prompt through the PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN environment variable or the --config.verify-deps-before-run flag #​13816. Only the boolean values were accepted before, so a string value was silently dropped.

  • pnpm version <bump> with --dry-run no longer edits package.json files. It now only reports the bumps it would make, and skips the working tree check, the version lifecycle scripts, the commit, and the tag pnpm/pnpm#13953.

Platinum Sponsors

Bit
OpenAI

Gold Sponsors

Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v11.22.0: pnpm 11.22

Compare Source

Minor Changes

  • Added pnpm cache path, which prints the directory pnpm uses for its metadata cache. CI setups can use it to cache that directory — including the lockfile verification log, which lets a job skip re-checking an unchanged lockfile against the configured supply-chain policies.

  • --config.config-dir no longer reaches the config through a project's pnpm-workspace.yaml, and neither do the --config. spellings of the other settings a project manifest may no longer contribute (--config.pnpm-home-dir, --config.workspace-dir, --config.global-pkg-dir, --config.root-project-manifest-dir). None of them was ever a supported way to set those directories: pnpm resolves them from the environment, and these flags took effect only because the project-manifest merge re-applied the command line afterwards. The dedicated flags, such as --dir and --global-dir, are unaffected #​13629.

  • pnpm config set refuses to write a setting to a project's pnpm-workspace.yaml that pnpm does not read from there, rather than leaving a key in the file that does nothing. Those settings are configDir, pnpmHomeDir, stateDir and the others that name machine-level state. The command fails with ERR_PNPM_CONFIG_SET_NOT_A_PROJECT_SETTING, naming where the setting does belong when it belongs somewhere. pnpm config delete still clears one that a file already carries, in whichever spelling it uses #​13629.

  • Added a new setting minimumReleaseAgeExcludePrune. When enabled, pnpm add, pnpm update, and pnpm remove prune the entries of minimumReleaseAgeExclude in pnpm-workspace.yaml that the freshly written lockfile no longer resolves: versions that are gone are dropped (an entry is removed once none of its versions remain), and entries for packages that are no longer in the lockfile are removed too. Name patterns (@scope/*) are always kept. The cleanup is skipped when the install's lockfile does not cover the whole workspace (sharedWorkspaceLockfile: false), since entries another project still needs would look stale.

    Renamed cleanupUnusedCatalogs to catalogPrune, so that catalog pruning and release-age exclude pruning use one vocabulary. cleanupUnusedCatalogs continues to work; when both are set, catalogPrune wins.

  • A project's pnpm-workspace.yaml can no longer choose where pnpm keeps its credentials, its own installation, or the registry it downloads its next version from. One of those settings is configDir, which decided where pnpm login writes the granted token. bin, dir, globalBinDir, globalDir, npmrcAuthFile, pnpmHomeDir, stateDir, userconfig and workspaceDir are ignored there now too, and pnpm warns about the ones it finds. cacheDir and storeDir are unaffected #​13629.

  • Resolving a Node.js runtime version (devEngines.runtime / runtime: specifiers) is now much faster: the per-version release metadata is cached in the pnpm cache directory after its signature is verified, and an exact stable version such as runtime:22.23.2 no longer downloads the Node.js release index. A pinned runtime whose metadata was fetched once resolves without any network access, which removes the noticeable delay on the first node invocation in a project pinning an already-downloaded runtime #​13899.

Patch Changes

  • Fixed intermittent ERR_PNPM_ENOENT and ERR_PNPM_ENOTEMPTY errors while renaming _tmp_* directories during installation with nodeLinker: hoisted, in workspaces that also use patchedDependencies.

  • pnpm add no longer re-resolves the dependency graph when pnpm-lock.yaml already holds a version satisfying the request — promoting a transitive dependency to a direct one, or adding to a second workspace package what a first one already depends on, now only saves the dependency in package.json and records its importer entry. A satisfying locked version is necessary but not sufficient: the install still falls back to a full resolution for a dist tag, an alias, a workspace:/catalog:/git/tarball specifier, --save-peer, an overridden package, a catalogMode other than manual, and — under resolutionMode: time-based or lowest-direct, which resolve a direct dependency to the low end of its range — a range several locked versions satisfy.

  • Global installs now switch over atomically. The command shims in the global bin directory point at a stable per-package link rather than at the directory a particular install produced, so pnpm add -g and pnpm update -g activate a new version by moving that one link instead of rewriting every shim. A command can no longer be missing from PATH while an install is in progress, and a failed install leaves the previous version in place.

  • pnpm audit --fix and pnpm audit --fix update no longer add minimumReleaseAgeExclude entries for patched versions that were published before the minimumReleaseAge cutoff. The publish time of each minimum patched version is now checked against the registry metadata, and only versions young enough to be blocked by the age gate get an exclusion entry #​11563.

  • pnpm add <pkg>@<version> and pnpm update <pkg>@<version> under a non-manual catalogMode now move the catalog entry's resolution to the requested version. Previously, when the catalog entry was a range that covered the requested version but resolved to a different one, the request was dropped silently: nothing was installed, nothing was written, and no error was raised.

  • A project that wasn't part of an install that moved a catalog entry now follows the entry the next time it is installed. It used to keep the version the entry resolved to before — a version the entry no longer allowed — and no later install corrected it, so one catalog entry ended up resolved to two versions.

  • pnpm add <pkg>@<version> and pnpm update <pkg>@<version> under catalogMode: strict no longer fail with ERR_PNPM_CATALOG_VERSION_MISMATCH when the catalog entry is a range that the wanted version satisfies. The dependency keeps using the catalog; only a version that really falls outside the catalog's range is rejected #​13715.

  • A changed catalogs or pnpm.overrides block no longer has to be the only change for pnpm install to update the lockfile in place. Editing an override while also removing a dependency, or changing a catalog entry in the same commit as a range bump, is now absorbed in one pass instead of re-resolving the whole dependency graph #​13799.

    Fixed the lockfile an in-place override update wrote when the overridden package was also a catalog entry: the entry kept the version it had before the override moved the package. The same could happen in reverse, when a catalog entry moved a package an override pins. Both cases now re-resolve instead.

  • pnpm install now updates the lockfile in place even when several kinds of changes happened since the last install — for example a removed dependency together with a widened ignoredOptionalDependencies list, or a dependency edit alongside a patch or settings change. Previously any combination of changes forced a full re-resolution #​13763.

  • pnpm deploy injects workspace dependencies again, so the deploy directory is self-contained instead of symlinking back into the source workspace #​13754. Enabling injectWorkspacePackages with dedupeInjectedDeps disabled now also rewrites already-linked workspace dependencies to injected copies.

  • pnpm deploy --no-optional no longer writes a lockfile whose snapshots reference optional dependencies that the deploy excluded.

  • Removing the last dependency that references a catalog entry via the fast lockfile update no longer leaves the stale catalog entry in pnpm-lock.yaml.

  • A git dependency whose clone (or shallow fetch) fails now reports which package it belongs to, under the ERR_PNPM_GIT_FETCH_FAILED code, with credentials in the repository URL redacted. When the lockfile records an SSH remote, the error also explains that fetching it needs an SSH key for that host, and that a lockfile entry written before pnpm v11.21 can be re-recorded over HTTPS with pnpm update <package> #​13743.

  • An integrity recorded on a git dependency's resolution (resolution: {type: git, repo, commit, integrity: sha512-…}) is no longer treated as a checksum. pnpm never verifies a git checkout against such a hash — the commit pins the content — so it is now dropped when the lockfile is rewritten, and pnpm sbom no longer republishes it as a CycloneDX/SPDX checksum. Lockfiles carrying one also load again instead of failing with ERR_PNPM_BROKEN_LOCKFILE #​13042.

    pnpm sbom now also publishes the checksum of a type: binary runtime archive, which pnpm does verify.

  • A git dependency whose git ls-remote fails now reports the ERR_PNPM_GIT_RESOLVE_FAILED code, naming the dependency instead of printing a bare git invocation, with credentials in the repository URL redacted. A specifier that does not ask for SSH resolves over HTTPS, because the URL recorded in the lockfile has to work on every machine that installs it, so the error explains how to substitute the transport on a machine that can only reach the host over SSH (git config --global url."git@<host>:".insteadOf "https://<host>/") #​13743.

    A missing git executable is reported as one, instead of surfacing the raw failure to start the process.

    Credentials embedded in a git specifier are redacted from the "Could not resolve <ref> to a commit of <repo>" errors too.

    Resolving a public repository makes one git ls-remote round-trip instead of two.

  • pnpm install after moving a dependency between dependencies, devDependencies, and optionalDependencies now updates the lockfile in place instead of re-resolving the whole dependency graph #​13696.

  • syncInjectedDepsAfterScripts no longer fails with ERR_PNPM_UNSUPPORTED_INODE_TYPE when a workspace package contains an inode that is neither a file nor a directory, such as the FIFO 1Password's environments create for .env. Such an inode cannot be hardlinked into the injected copy, so it is skipped and the rest of the package still syncs #​13550.

    syncInjectedDepsAfterScripts also no longer fails with EEXIST when a workspace package replaced a file with a directory of the same name since the injected copy was last synced.

  • syncInjectedDepsAfterScripts no longer fails with ENOTDIR when a workspace package replaced a directory with a file of the same name and the injected copy still held that directory's contents.

  • syncInjectedDepsAfterScripts now removes the bin link of a bin the script dropped. Previously only new bins were linked, so a build step that stopped declaring one left its shim behind, pointing at a command that was no longer there.

  • syncInjectedDepsAfterScripts now identifies a file by its device as well as its inode number. An inode number is only unique within one filesystem, so on its own it could match an unrelated file on another device and leave that path stale in the injected copy.

  • pnpm store prune no longer deletes the lockfile verification log. The log records which lockfile passed which supply-chain policies, so it stays valid across a prune of the store; keeping it lets the next install skip re-verifying an unchanged lockfile.

  • Widening a dependency's range no longer leaves the project on an older version. The lockfile update now points the project at the highest version of that dependency already in the lockfile that satisfies the new range — matching what a full resolution records — instead of keeping the locked version whenever it happened to satisfy, which could leave a duplicate behind. A range change that only an already-locked version satisfies is now also handled without re-resolving #​13778.

  • resolutionMode is no longer ignored when minimumReleaseAge is in effect. lowest-direct and time-based pick the lowest satisfying version of a direct dependency again; previously any active release-age cutoff — including the built-in default — silently forced the highest, so resolutionMode only worked when minimumReleaseAge: 0 was set explicitly #​13752.

  • Adding a package to a workspace no longer forces a full re-resolution when every dependency it declares is already locked for a sibling. The lockfile update writes the new project's importer entry from the versions the lockfile already holds; a dependency no locked version satisfies still reaches the resolver #​13696.

  • pnpm config delete <key> no longer fails with ENOENT when the config file it would edit does not exist. Clearing a setting that was never set is a no-op #​13651.

  • Changing a pnpm.overrides entry to a version range now updates the lockfile in place when a version the lockfile already holds satisfies the range, instead of re-resolving the whole dependency graph. Only exact versions were handled before #​13696.

  • Changing a parent-scoped pnpm.overrides entry ("parent>child": "2.0.0") now updates the lockfile in place instead of re-resolving the whole dependency graph. Only the named parent's dependency moves; every other package keeps the version it had #​13795.

  • Removing a dependency, or moving one to another already-locked version, no longer re-resolves the whole dependency graph just because some package resolves a peer with the same name. The lockfile update now compares the peer suffixes against the exact name@version the removal severed, so a suffix that names a different — still present — version of that dependency is left alone #​13781.

  • Projects with a pnpmfile now use the fast lockfile update paths: an unchanged pnpmfile (proven by the recorded pnpmfileChecksum) no longer forces a full re-resolution for removals, dependency group moves, compatible range changes, and the other in-place lockfile rewrites #​13696.

  • A lockfile entry whose resolution is unchanged no longer loses its recorded deprecated marker when a registry serves the package's metadata inconsistently — re-resolving to the same version keeps the deprecation instead of silently dropping the line #​13846.

  • pnpm prune is now recursive by default inside a workspace, just like pnpm install. This fixes pnpm prune --prod in a workspace root emptying the node_modules directories of the other workspace projects, dropping the links to the workspace packages they depend on in production #​13718.

  • A setting written in kebab-case in the global config.yaml is now reported instead of being silently ignored #​13650.

  • pnpm remove no longer re-resolves the dependency graph. The removed dependency's entries are dropped from pnpm-lock.yaml and anything they made unreachable is pruned, without registry access. The install still falls back to a full resolution when a surviving package resolves a peer dependency through the removed one.

  • Removing a package from a workspace no longer forces a full re-resolution. The lockfile update drops the departed project's importer entry and prunes whatever only it depended on. A project that is still linked from a surviving project continues to be reported as an error #​13696.

  • An install sharing a global virtual store no longer removes an incomplete package directory that another importer is still writing, which could fail with failed to remove existing directory ... prior to swap: Directory not empty. Such a directory is now repaired in place, and a package file left damaged by an interrupted install is restored instead of being kept.

  • pnpm sbom no longer emits components for optional platform-specific dependencies that cannot be installed on the current platform (for example, the native @rolldown/binding-* variants for other operating systems). Such packages are present in the lockfile but are never downloaded, so their license (and other metadata) could not be resolved and they appeared in the SBOM without one. pnpm sbom --lockfile-only still describes the whole lockfile graph, which is platform-independent by design.

  • An ssh:// git dependency pointing at a bracketed IPv6 host, such as ssh://[::1]/repo.git, is resolved now. Its colons were read as an SCP-style path separator, which turned the address into [:/1] and left the specifier unresolvable. Applies to both the TypeScript CLI and pacquet.

    In the TypeScript CLI, an ssh:// git dependency written without user info — ssh://git.example.com/team/repo.git, git+ssh://git.example.com:2222/team/repo.git — no longer fails with TypeError: Cannot read properties of undefined (reading 'includes'). Only the user@host form worked before.

  • packageExtensions is now validated when the configuration is read, so a malformed entry (for instance a dependency range set to null) fails with an actionable error instead of crashing later during peer dependency resolution #​13756.

  • Projects using resolutionMode: time-based now benefit from the fast lockfile update paths. A removal, a dependency group move, or a compatible range change no longer forces a full re-resolution just because the lockfile carries a time field #​13696.

  • An install that drops the last dependent of a patched package no longer updates the lockfile in place and succeeds silently. Removing a dependency, widening ignoredOptionalDependencies, or adding a removal override could each prune the package while the patch stayed configured; such an install now falls back to a full resolution, which reports the unused patch with ERR_PNPM_UNUSED_PATCH. Under allowUnusedPatches, where the lockfile update is kept, the same install now warns that the patch went unused instead of saying nothing #​13827.

Platinum Sponsors

Bit
OpenAI

Gold Sponsors

Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

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
recharts/recharts (recharts)

v3.10.1

Compare Source

What's Changed

  • fix(Pie): pass computed innerRadius/outerRadius to Label children via PolarLabelContextProvider by @​0007aadil in #​7458
  • chore(deps): bump immer from 11.1.9 to 11.1.15 by @​dependabot[bot] in #​7575
  • fix(tooltip): fall back to index-based search when label-based search returns undefined for allowDuplicatedCategory=false by @​hxy-asdw in #​7573
  • fix(bar): keep barGap correct when maxBarSize clamps the bar width (#​2774) by @​sobol-sudo in #​7582

New Contributors

Full Changelog: https://github.com/recharts/recharts/compare/v3.10.0...v3.10.1

v3.10.0

Compare Source

What's Changed

Legend position

Legend now supports position and offset props, same as Label and LabeList. This replaces the previous align and verticalAlign for a more convenient positioning, and fixes couple visual bugs too. See https://recharts.github.io/en-US/examples/LegendPosition/

XAxis auto height

XAxis now supports height="auto" prop, similar to YAxis width="auto".

  • feat(XAxis): support height="auto" to size the axis to its tick labels by @​kimlj in #​7570
Other features
Bugfixes

New Contributors

Full Changelog: https://github.com/recharts/recharts/compare/v3.9.2...v3.10.0

v3.9.2

Compare Source

What's Changed

New Contributors

Full Changelog: https://github.com/recharts/recharts/compare/v3.9.1...v3.9.2

v3.9.1

Compare Source

What's Changed

New Contributors

Full Changelog: https://github.com/recharts/recharts/compare/v3.9.0...v3.9.1

typescript-eslint/typescript-eslint (typescript-eslint)

v8.72.2

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.72.1

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.72.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.71.2

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.71.1

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.71.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.70.1

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.70.0

Compare Source

🩹 Fixes
  • eslint-plugin: [no-deprecated] report deprecated imported values used in object shorthand properties (#​12780)
❤️ Thank You

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.69.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.68.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.67.0

Compare Source

🚀 Features
  • typescript-eslint: export basic globs for using tseslint (#​12105)
❤️ Thank You

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.66.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.65.0

Compare Source

🚀 Features
  • add warning when TS 7 is detected (#​12529)
❤️ Thank You

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.64.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.63.0

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.62.1

Compare Source

This was a version bump only for typescript-eslint to align it with other projects, there were no code changes.

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.


Configuration

📅 Schedule: (in timezone Europe/Berlin)

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

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • 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/pnpm/npm/pnpm)) | [`11.9.0` → `11.28.11`](https://renovatebot.com/diffs/npm/pnpm/11.9.0/11.28.11) | ![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.28.11?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.9.0/11.28.11?slim=true) | | [recharts](https://github.com/recharts/recharts) | [`3.9.0` → `3.10.1`](https://renovatebot.com/diffs/npm/recharts/3.9.0/3.10.1) | ![age](https://developer.mend.io/api/mc/badges/age/npm/recharts/3.10.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/recharts/3.9.0/3.10.1?slim=true) | | [typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint) ([source](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint)) | [`8.62.0` → `8.72.2`](https://renovatebot.com/diffs/npm/typescript-eslint/8.62.0/8.72.2) | ![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.72.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.62.0/8.72.2?slim=true) | --- ### Release Notes <details> <summary>pnpm/pnpm (pnpm)</summary> ### [`v11.28.11`](https://github.com/pnpm/pnpm/releases/tag/v11.28.11): pnpm 11.28.11 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.10...v11.28.11) pnpm 11.28.11 fixes frozen installs with `excludeLinksFromLockfile`, `pnpm link` in workspaces, `pnpm deploy` with dangling symlinks, and `verifyDepsBeforeRun` starting needless installs. ##### Patch Changes ##### Installing packages - `pnpm deploy` now keeps a symlink in the project whose target is missing from the source, such as a link into a `node_modules` directory that was removed after the build. Deploy used to fail with `ENOENT` on such a link [#&#8203;17571](https://github.com/pnpm/pnpm/issues/17571). - A package with `bundledDependencies` and a build script now keeps its bundled dependencies when it is restored from the side-effects cache [#&#8203;17523](https://github.com/pnpm/pnpm/issues/17523). - `pnpm install` now links the runtime that an earlier `pnpm install --no-runtime` skipped [#&#8203;17542](https://github.com/pnpm/pnpm/issues/17542). - Commands of a package whose `bin` paths contain excess parent directory segments, such as `../dist/cli.js`, are no longer missing. Such paths now resolve inside the package [#&#8203;17586](https://github.com/pnpm/pnpm/issues/17586). - Generated POSIX shell shims now quote their paths, so shell special characters in a path stay literal. - A repeat `pnpm install` now rewrites the bin shims after `extendNodePath` changes. Before, it reported "Already up to date" and the shims kept the `NODE_PATH` of the previous setting. ##### Lockfile and resolution - `pnpm install --frozen-lockfile` now accepts the lockfile it wrote with `excludeLinksFromLockfile` and `linkWorkspacePackages` on, when a project depends on a workspace package through a plain version range or a `catalog:` entry. It used to fail with `ERR_PNPM_OUTDATED_LOCKFILE`. - `pnpm install --frozen-lockfile`, `pnpm approve-builds`, and `pnpm rebuild` now accept a lockfile that resolves a `*` dependency to a prerelease `latest` version. pnpm wrote such a lockfile and then reported it as outdated [#&#8203;17594](https://github.com/pnpm/pnpm/issues/17594). - Packages from the default registry keep plain lockfile keys, even when a prefix such as `npmjs` points at the registry set as `registry`. A dependency written with such a prefix shares the plain entry of the same package. The next install rewrites keys that earlier versions qualified this way [#&#8203;17575](https://github.com/pnpm/pnpm/issues/17575). - Relative local paths in root `overrides` now resolve from the workspace root when each project has its own lockfile [#&#8203;17691](https://github.com/pnpm/pnpm/issues/17691). Installing a local directory dependency no longer fails when another project's install is writing a lockfile in that directory. - Peer deduplication no longer gives a project different copies of a dependency across direct and transitive paths when an optional peer has no provider [#&#8203;17666](https://github.com/pnpm/pnpm/issues/17666). - A Node.js version range such as `>=26.13`, for example in `devEngines.runtime`, now resolves to the newest stable release that satisfies it. pnpm picks a prerelease only when no stable release matches [#&#8203;17516](https://github.com/pnpm/pnpm/issues/17516). ##### verifyDepsBeforeRun - With `verifyDepsBeforeRun`, `pnpm run` and `pnpm exec` now report dependencies as out of date after a dependency is added to the `package.json` of a local directory dependency, such as `"lib": "file:../lib"`. Before, the command ran without the new dependency installed. - `verifyDepsBeforeRun` no longer reports dependencies as out of sync when only the `version` field of a single-project repository changed [#&#8203;17560](https://github.com/pnpm/pnpm/issues/17560). The same holds for a workspace project that no dependency can resolve to. A script run after such a change no longer starts an install first. ##### pnpm link - In a workspace, `pnpm link <dir>` now adds the `link:` dependency to the `package.json` of the project where the command runs, not to the workspace root's `package.json`. The link is created in that project's `node_modules`, as documented. The override is still written to the root `pnpm-workspace.yaml`. - `pnpm link` with several paths now records every linked package in the `overrides` of `pnpm-workspace.yaml`. Some of them could be missing before. - `pnpm link` now fails without changing `package.json` or `pnpm-workspace.yaml` when the linked package's name is not a valid npm package name. It used to write that name to both files, which made every later install fail [#&#8203;17475](https://github.com/pnpm/pnpm/issues/17475). ##### pnpm update - `pnpm update` with only negated selectors, such as `pnpm update '!foo'`, now leaves the dependencies listed in `update.ignoreDeps` unchanged [pnpm/tasks#243](https://github.com/pnpm/tasks/issues/243). - `pnpm update --depth 0` without selectors now does nothing when every direct dependency is listed in `update.ignoreDeps`. Before, it failed with `ERR_PNPM_NO_PACKAGE_IN_DEPENDENCIES` [pnpm/tasks#251](https://github.com/pnpm/tasks/issues/251). ##### Store and self-update - `pnpm store prune` now keeps packages linked from a configured modules directory [pnpm/tasks#230](https://github.com/pnpm/tasks/issues/230). - `pnpm store status` no longer reports untouched packages as modified when the global virtual store is enabled. If the installed global-store layout cannot be verified, the command reports `ERR_PNPM_STORE_STATUS_UNVERIFIABLE` and asks for a reinstall [#&#8203;17631](https://github.com/pnpm/pnpm/issues/17631). - `pnpm store add` now fails right away with `ERR_PNPM_FROZEN_STORE_WRITE` when `frozenStore` is enabled. It used to retry each download for minutes before failing, or fail with a SQLite error on an empty store. - `pnpm self-update` now reinstalls a cached engine if its executable cannot run. This repairs shared store entries damaged by an earlier install [#&#8203;17582](https://github.com/pnpm/pnpm/issues/17582). <!-- 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> <td align="center" valign="middle"> <a href="https://www.cloudflare.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/cloudflare.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/cloudflare_light.svg" /> <img src="https://pnpm.io/img/users/cloudflare.svg" width="160" alt="Cloudflare" /> </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> <td align="center" valign="middle"> <a href="https://syntax.fm/?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/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> <!-- sponsors end --> ### [`v11.28.10`](https://github.com/pnpm/pnpm/releases/tag/v11.28.10): pnpm 11.28.10 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.9...v11.28.10) pnpm 11.28.10 stops `pnpm store prune` from deleting other stores when `cacheDir` points to their parent directory. It also fixes globally installed commands that load hoisted dependencies, and repeat installs that missed changes to local dependencies. ##### Patch Changes ##### Installing packages - `pnpm store prune` preserves other stores and global package data when `cacheDir` points to their parent directory. - Commands installed with `pnpm add --global` now find the dependencies that pnpm hoists for their package. A package that loads a dependency it does not declare, such as a native addon's platform-specific package, failed with "Cannot find module". Reinstall such a package with `pnpm add --global` to update its existing command [#&#8203;17503](https://github.com/pnpm/pnpm/issues/17503). - `pnpm prune --prod` no longer fails with `ERR_PNPM_EXDEV` when `node_modules` was copied from an earlier Docker build stage [#&#8203;17424](https://github.com/pnpm/pnpm/issues/17424). - `pnpm install` now retries a Node.js runtime zip download when the connection drops partway through. A download that still fails names its URL. Before, a single dropped connection ended the install with `terminated` [#&#8203;17411](https://github.com/pnpm/pnpm/issues/17411). - With the global virtual store, a change to a dependency of one package in a dependency cycle now gives every package in that cycle a new directory. Before, the other packages kept their directories and still linked the old copy of the changed package, so the project could load two copies of it [#&#8203;17466](https://github.com/pnpm/pnpm/issues/17466). Packages in a dependency cycle, and packages that depend on one, move to new global virtual store directories once after this update. Those that run a build miss the side-effects cache once. - `pnpm install` and `pnpm rebuild` now refresh privately hoisted `.bin` shims in `node_modules/.pnpm/node_modules/.bin` after a dependency build replaces a script target with a native executable [#&#8203;17402](https://github.com/pnpm/pnpm/issues/17402). - The Node.js `latest` selector now chooses the newest stable release [#&#8203;17490](https://github.com/pnpm/pnpm/issues/17490). - The standalone `@pnpm/exe` builds now embed Node.js 26.13.0. ##### Repeat installs and lockfiles - `pnpm install` now resolves a local directory again after its `package.json` changes when an override or a package extension adds it to the dependencies of a registry package. `pnpm install --frozen-lockfile` fails on a lockfile that still records the old dependencies of such a directory [#&#8203;17486](https://github.com/pnpm/pnpm/issues/17486). - With `injectWorkspacePackages` and per-project lockfiles, `pnpm install` now updates a project's lockfile when a local tarball that an injected workspace project depends on is replaced. The project's lockfile kept the old version and integrity before. - `pnpm install` now detects a change to a local tarball or directory that only a pnpmfile `readPackage` hook depends on. A repeat install reported "Already up to date" and kept the old contents before [pnpm/tasks#227](https://github.com/pnpm/tasks/issues/227). - `pnpm install` now relinks a `workspace:` or `link:` dependency whose link was deleted from `node_modules`. It used to report "Already up to date" and leave the link missing [#&#8203;17485](https://github.com/pnpm/pnpm/issues/17485). - Merging git branch lockfiles now keeps a workspace project whose directory is named `__proto__`. It was dropped from the merged lockfile before [pnpm/tasks#59](https://github.com/pnpm/tasks/issues/59). ##### Adding and publishing packages - `pnpm add` no longer rewrites a catalog entry set to the dist-tag that the dependency resolves through. For example, an entry `beta` stays `beta` after `pnpm add foo@beta` or `pnpm add foo`. Before, the entry was replaced with the version the tag pointed to [pnpm/tasks#225](https://github.com/pnpm/tasks/issues/225). - `pnpm pack` and `pnpm publish` now always include the binary file declared by a string `bin` field in `package.json`, even when `files` or `.npmignore` would otherwise exclude it. - When the version or range given to `pnpm unpublish` matches every published version, the error now says so and shows the same command with `--force`. It suggested running `pnpm unpublish <pkg>@<version>`, the command that had just failed. ##### Running commands - Every command, including `pnpm --version`, `pnpm self-update`, and invocations with unknown flags, now applies the same `packageManager` and `devEngines.packageManager` settings when switching to the pinned pnpm version or recording it in `pnpm-lock.yaml`. `--config.<key>` flags and `lockfileDir` now reach the version switch and lockfile sync on every entry point. Unreadable settings in `pnpm-workspace.yaml` or the global `config.yaml` that do not affect the pin decision no longer block the version switch [pnpm/tasks#222](https://github.com/pnpm/tasks/issues/222). - On Windows, the shell shim of a `.cmd` or `.bat` bin now runs it under Git Bash when MSYS argument conversion is off, such as with `MSYS_NO_PATHCONV=1` or `MSYS2_ARG_CONV_EXCL='*'`. The shim used to start an interactive cmd.exe prompt [#&#8203;17480](https://github.com/pnpm/pnpm/issues/17480). - `pnx` and `pnpm create` now run the command in the directory selected by `--dir` or `--workspace-root`. Without either flag, the command still runs in the directory pnpm was started in. - The error for a dependency with an invalid name in a project's manifest now names the project's directory. It used to say only "The current package", which did not tell which workspace project to fix [#&#8203;17475](https://github.com/pnpm/pnpm/issues/17475). <!-- 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> <td align="center" valign="middle"> <a href="https://www.cloudflare.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/cloudflare.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/cloudflare_light.svg" /> <img src="https://pnpm.io/img/users/cloudflare.svg" width="160" alt="Cloudflare" /> </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> <td align="center" valign="middle"> <a href="https://syntax.fm/?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/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> <!-- sponsors end --> ### [`v11.28.9`](https://github.com/pnpm/pnpm/releases/tag/v11.28.9): pnpm 11.28.9 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.8...v11.28.9) This release fixes a crash on registry responses with too many content encodings ([GHSA-xjj6-f33q-929c](https://github.com/advisories/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](https://github.com/advisories/GHSA-xjj6-f33q-929c). - `pnpm install` now 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 default `workspaceConcurrency` respects 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 [#&#8203;17382](https://github.com/pnpm/pnpm/issues/17382). ##### Repeat installs and changed settings - A repeat `pnpm install` now acts on a change to these settings. Before, it reported "Already up to date". - `storeDir` or `virtualStoreDir`: it recreates `node_modules`. - `virtualStoreDirMaxLength`: it renames the virtual store directories. - `dangerouslyAllowAllBuilds` turned on: it runs the builds it skipped. - `trustLockfile` turned off: it verifies the lockfile. - `pnpm add`, `pnpm remove`, and `pnpm update` now fail when the `node-linker` setting differs from the one recorded in `node_modules`. A `pnpm install` of the whole workspace recreates `node_modules` with the new `node-linker`, and an install filtered to some projects fails [pnpm/tasks#203](https://github.com/pnpm/tasks/issues/203). - An install filtered to some workspace projects now fails if `node_modules` was installed with a different `nodeLinker`, `hoistPattern`, `publicHoistPattern`, store, or virtual store. Before, it recreated `node_modules` and left the projects it skipped without their dependencies. A `pnpm install` of the whole workspace still recreates `node_modules` [pnpm/tasks#217](https://github.com/pnpm/tasks/issues/217). - `pnpm install` now takes its fast path in a workspace with `patchedDependencies` when the previous install ran with another major version of pnpm. - `pnpm install` now relinks the bins of a workspace package when its `bin` field changes, including with `--frozen-lockfile` and an unchanged lockfile. A filtered install relinks them in the selected projects, and the next install that covers the remaining projects relinks them there [#&#8203;17324](https://github.com/pnpm/pnpm/issues/17324). - `pnpm install` now removes command shims from `node_modules/.bin` when a workspace dependency renames or removes an entry from its `bin` field [pnpm/tasks#211](https://github.com/pnpm/tasks/issues/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 in `node_modules`. - `pnpm run` and `pnpm exec` no longer report the dependencies as out of date after a lockfile change when `dedupePeers` is `true` [#&#8203;17322](https://github.com/pnpm/pnpm/issues/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 in `pnpm-lock.yaml` and installed once. The lockfile key names the registry a package resolved from. When that registry declares a prefix, through `prefix` in `registries` or through `namedRegistries`, 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 and `instanceof` checks 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 install` re-keys those entries, which shows up as a lockfile diff. Commit it. `pnpm install --frozen-lockfile` installs the lockfile as recorded. - `pnpm install` now resolves a scope's packages again when the scope is routed to another registry in `registries`. 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, and `pnpm install --frozen-lockfile` is 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`, a `workspace:` dependency written as a relative path, such as `workspace:../lib-a`, in a workspace package now resolves from that package's directory [#&#8203;17284](https://github.com/pnpm/pnpm/issues/17284). - Fixed `pnpm install` failing with `ERR_PNPM_UNSUPPORTED_PROTOCOL` when a workspace package injected through a relative path, such as `workspace:../lib`, has `catalog:` dependencies. Their catalog entries now resolve the way they do for a package injected by name [#&#8203;17280](https://github.com/pnpm/pnpm/issues/17280). - `pnpm install` now applies the `serverType` registry 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 `pnpr` value to the `serverType` registry setting. pnpm leaves the tarball URLs of a pnpr registry out of `pnpm-lock.yaml`. - A `registries` entry whose `prefix` is `__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 to `work:` in `namedRegistries`, failed on the server [pnpm/tasks#204](https://github.com/pnpm/tasks/issues/204). ##### Registries, proxies, and downloading pnpm - The proxy settings `httpProxy`, `httpsProxy`, `noProxy`, `proxy`, and `noproxy` set in the global `config.yaml`, through `PNPM_CONFIG_HTTPS_PROXY` and the matching variables, or as `--config.httpsProxy` on the command line now apply to `pnpm self-update` and to the download of the pnpm version pinned in `packageManager`. Previously, these requests read the proxy only from `.npmrc` and the `HTTPS_PROXY` family of variables [pnpm/tasks#215](https://github.com/pnpm/tasks/issues/215). - When `https-proxy` is `false`, pnpm now downloads the pnpm version pinned by `packageManager` through the legacy `proxy` setting, as installs already do. Setting `proxy` to `false` now also stops that download from using the `HTTP_PROXY` environment variable. The signature check of the pinned pnpm now uses the same proxy and TLS settings as its download [pnpm/tasks#193](https://github.com/pnpm/tasks/issues/193). - `strictSsl` and `localAddress` set in the global `config.yaml`, through `PNPM_CONFIG_STRICT_SSL` and `PNPM_CONFIG_LOCAL_ADDRESS`, or on the command line now apply to `pnpm self-update` and to the download of the pnpm version pinned in `packageManager`. These requests read them from `.npmrc` only before. `--config.localAddress` now reaches them in the camelCase spelling too [pnpm/tasks#201](https://github.com/pnpm/tasks/issues/201). ##### Commands - `pnpm audit --ignore` and `pnpm audit --ignore-unfixable` now 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 --fix` and `pnpm audit --interactive` now fail with `ERR_PNPM_AUDIT_FIX_WITH_IGNORE` when combined with `--ignore` or `--ignore-unfixable`. Before, the fix ran and the ignore flags had no effect. - `pnpm ci --lockfile` and `pnpm ci --config.lockfile=true` no longer delete `pnpm-lock.yaml`. `pnpm ci` now always keeps the lockfile and runs a frozen install from it. - `pnpm deploy` now keeps a deployed symlink to a directory inside the project even if the directory is not among the deployed files, such as a link into `node_modules` [#&#8203;17288](https://github.com/pnpm/pnpm/issues/17288). - `pnpm pack` and `pnpm publish` again include the files of a `publishConfig.directory` that is reached through a symlink, together with its bundled dependencies [#&#8203;17390](https://github.com/pnpm/pnpm/issues/17390). - `pnpm -r publish --batch` now sends `PUT /-/pnpr/v0/publish`, the batch publish endpoint that pnpr serves. - `pnpm store prune` now keeps the packages that a project still uses when pnpm copied or cloned them into `node_modules`. These include patched packages, built packages, and every package installed with `packageImportMethod: copy`. Before, the prune removed them, and the next install downloaded them again [#&#8203;7192](https://github.com/pnpm/pnpm/issues/7192). - `pnpm store prune` now 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 [#&#8203;17374](https://github.com/pnpm/pnpm/issues/17374). - Output that fills the terminal, such as `pnpm run --stream` script output, is now written once. Before, every new line also rewrote all the lines already on screen [#&#8203;17387](https://github.com/pnpm/pnpm/issues/17387). - The warning about unrecognized settings now marks `symlinkedLockfileTargetDirs` as 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 --> ### [`v11.28.8`](https://github.com/pnpm/pnpm/releases/tag/v11.28.8): pnpm 11.28.8 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.7...v11.28.8) ##### Patch Changes - The standalone `@pnpm/exe` builds now embed Node.js 26.12.1. The previously embedded Node.js 26.0.0 still trusted the certificate authority intermediates that Node.js distrusted in October 2026, so a standalone pnpm accepted TLS certificates issued under them. <!-- 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 --> ### [`v11.28.7`](https://github.com/pnpm/pnpm/releases/tag/v11.28.7): pnpm 11.28.7 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.6...v11.28.7) This release rejects registry metadata that names a different package than the one requested, applies `trustPolicy` to the pnpm version a project pins, and caps unpacked package size with `maxTarballUnpackedSize`. It also removes support for registry revisions, fixes `verifyDepsBeforeRun` after filtered installs, and finishes commands with their own exit code when a pipe reader exits early. ##### Patch Changes ##### Security - pnpm now fails with `ERR_PNPM_REGISTRY_NAME_MISMATCH` if a registry returns metadata for a package other than the one requested. Before, pnpm installed the package under the name in the metadata, so `allowBuilds` rules for the requested package did not apply to it. - pnpm now applies `trustPolicy` to the pnpm version a project pins in `packageManager` or `devEngines.packageManager`. A pinned version whose trust evidence was downgraded fails the command before pnpm switches to it or records it in the lockfile [#&#8203;16319](https://github.com/pnpm/pnpm/issues/16319). - `minimumReleaseAgeExcludePrune` and `trustPolicyExcludePrune` now keep exclusions for resolved configuration dependencies and their transitive dependencies [#&#8203;17142](https://github.com/pnpm/pnpm/issues/17142). - Added the `maxTarballUnpackedSize` setting. `pnpm install` fails with `ERR_PNPM_TARBALL_TOO_LARGE` when the files of one package unpack to more than this many bytes, 4 GiB by default [pnpm/tasks#81](https://github.com/pnpm/tasks/issues/81). ##### Resolving dependencies - Registry revisions are no longer supported. pnpm now fails with `ERR_PNPM_REGISTRY_REVISIONS_UNSUPPORTED` on registry metadata that selects a revision, on a `+rN` version specifier, and on a lockfile entry with a `revision` field. `pnpm update --patches` is removed. - When `pnpm install` resolves a dependency again, it now reuses a version that the install already resolved for the same package, as a fresh install does. Before, it kept the version the lockfile pinned and added a second copy of the package. A locked version still stays when nothing else in the install prefers another version. To pin a transitive dependency on purpose, use `overrides` [#&#8203;17084](https://github.com/pnpm/pnpm/issues/17084). - When another workspace project adds a different version of a package, a project's auto-installed peer on that package now moves to the version a fresh install picks. It used to stay on its locked version while any other project still accepted that version [#&#8203;17058](https://github.com/pnpm/pnpm/issues/17058). - An optional peer that pnpm adds to a project now keeps the version the lockfile recorded for that project only while the dependency graph still holds it. Otherwise it follows its provider to a version the graph holds. Before, pnpm kept a higher version that only the lockfile held, which left two copies of the peer [#&#8203;16443](https://github.com/pnpm/pnpm/issues/16443). - A package that lists the same dependency in `dependencies` and as an optional peer now gets the peer bound when a project adds a provider for it later. The lockfile now records every peer a package declares, including one its own dependency supplies [#&#8203;17056](https://github.com/pnpm/pnpm/issues/17056). - `pnpm install --prod` no longer drops a dependency that a package declares both as an optional peer and as its own dependency, when the package resolved it as its own dependency and a dev dependency provides the same package under another alias. - pnpm now measures a `pnpm.overrides` entry written as a `workspace:` path, such as `workspace:./packages/foo`, from the directory holding `pnpm-workspace.yaml`. It used to be measured from each package the override rewrote. The install then linked a directory that does not exist, or failed if workspace packages were injected [#&#8203;17010](https://github.com/pnpm/pnpm/issues/17010). - `pnpm install` now removes config dependencies that are no longer declared, including when the entire `configDependencies` setting is removed. Frozen installs reject a lockfile that still records removed config dependencies. - `pnpm add` now reads the package name correctly from a tarball URL under a registry URL that has a path, such as `https://example.com/npm/`. Before, the registry path became part of the name, so a scoped package failed with `ERR_PNPM_INVALID_PACKAGE_NAME`. - `pnpm add` no longer warns that a gist dependency was replaced from a different source when the new specifier names the same gist in another form, such as `gist:<id>` and `https://gist.github.com/<user>/<id>`. - With `minimumReleaseAge` set, pnpm now revalidates a package's cached full metadata with a single ETag request so an unchanged registry answers with `304`, and keeps using the cached copy once the registry confirms it is current, even when the metadata does not list a publish time for every version. Previously, pnpm downloaded that metadata again whenever the cached copy was older than `minimumReleaseAge`. Packages listed in `minimumReleaseAgeExclude` also resolve from cached metadata without a registry request when the lockfile already has the version their range picks. ##### Linking node_modules and workspaces - Concurrent installs that import the same package into one project now all complete. One of them used to fail with `ENOTEMPTY` when its copy of the package collided with the copy another install had already placed [pnpm/tasks#48](https://github.com/pnpm/tasks/issues/48). - `pnpm install` no longer fails on macOS with `EISDIR` when it creates store directories in a group-writable store under a umask that removes owner read, such as `0o477`. - `pnpm install` now succeeds when `node_modules` is a symlink to an existing directory. Dependency hoisting previously rejected a symlinked `node_modules` as an invalid destination [#&#8203;17157](https://github.com/pnpm/pnpm/issues/17157). - A filtered `pnpm install --no-lockfile` with `hoistWorkspacePackages` now hoists every workspace project into `node_modules/.pnpm/node_modules`. It used to hoist only the selected projects [pnpm/tasks#168](https://github.com/pnpm/tasks/issues/168). - Filtered installs remove obsolete dependencies from the installed lockfile while preserving dependencies still needed by unselected projects. - With `sharedWorkspaceLockfile: false`, `pnpm install` now runs the `preResolution` hooks and custom resolvers and fetchers of the workspace root's pnpmfile for every project, next to the project's own. A global pnpmfile now runs once per project, and each project's lockfile records the checksum of the root pnpmfile when the project has none of its own. Before, a project's own pnpmfile replaced these root hooks, the global hooks ran twice, and edits to the root pnpmfile could go unnoticed. - `pnpm prune` now removes extraneous direct packages from `node_modules` when `package.json` and `pnpm-lock.yaml` are already in sync. `pnpm prune` also accepts `--filter` and `--recursive` to prune selected workspace projects without removing dependencies of unselected projects. ##### Injected workspace packages - `pnpm install --frozen-lockfile` now fails with `ERR_PNPM_OUTDATED_LOCKFILE` when the dependencies of an injected workspace package or local directory dependency no longer match the lockfile. This covers `sharedWorkspaceLockfile: false` [#&#8203;17008](https://github.com/pnpm/pnpm/issues/17008), a dependency changed to a different tarball URL or git commit [#&#8203;17129](https://github.com/pnpm/pnpm/issues/17129), and a change in a transitive injected or local directory dependency [#&#8203;17128](https://github.com/pnpm/pnpm/issues/17128). - `pnpm install --frozen-lockfile` no longer fails with `ERR_PNPM_OUTDATED_LOCKFILE` when an injected workspace package depends on a local directory under another name, such as `"renamed": "file:../b"` [#&#8203;17130](https://github.com/pnpm/pnpm/issues/17130). - An injected workspace dependency now becomes a link when its dependencies match the workspace package's own, also on an install that leaves the package's installed dependencies as they are. Before, such an install kept it as a copy [#&#8203;17094](https://github.com/pnpm/pnpm/issues/17094). - An injected workspace package that was linked now becomes a copy when the project that depends on it starts providing one of its peers at a version the package's own workspace context lacks. The link used to stay until that dependency was updated, so the package could not find the peer the project provides [#&#8203;17057](https://github.com/pnpm/pnpm/issues/17057). - An injected workspace package now keeps only the files its manifest lists after a lifecycle script or a script named in `syncInjectedDepsAfterScripts` rebuilds it. Before, these refreshes copied every file of the package directory into the injected copy, including files that `files` or `.npmignore` leave out. With `deployAllFiles: true` the copy still gets every file. - A script listed in `syncInjectedDepsAfterScripts` now keeps a package's links to its own files as links in the injected copies, the way `pnpm install` writes them. It no longer fails when the package links to one directory twice or links back to a directory above the link. `pnpm install` with `deployAllFiles` no longer fails on such a link back either. - A script listed in `syncInjectedDepsAfterScripts` now updates the injected copies of the package it ran in when `sharedWorkspaceLockfile` is `false` or the package publishes from `publishConfig.directory`. Before, those copies kept the files from the last install. ##### Running scripts and checking dependencies - When the reader of pnpm's output exits early, as in `pnpm outdated | head`, pnpm now finishes the command and exits with the command's own exit code [pnpm/tasks#133](https://github.com/pnpm/tasks/issues/133). It used to exit with code 0 at the first write to the closed pipe. That hid the result of commands such as `pnpm outdated` and stopped `pnpm clean` before it removed anything. - With `enableGlobalVirtualStore`, a Node.js resolve hook that a script registers now sees the importer as `context.parentURL` after pnpm's `NODE_PATH` fallback fails to find a bare specifier. Hooks that resolve tsconfig `paths` aliases from the importer failed with `ERR_MODULE_NOT_FOUND` [#&#8203;16979](https://github.com/pnpm/pnpm/issues/16979). - `pnpm run`, `pnpm exec`, and `pnpm restart` now pass the install flags they were given, such as `--lockfile-dir`, `--modules-dir`, `--store-dir`, `--offline`, and `--ignore-scripts`, to the `pnpm install` that `verifyDepsBeforeRun: install` starts. When that install leaves `node_modules` out of date, pnpm now prints a warning. - After `pnpm install --filter`, `pnpm run` and `pnpm exec` now notice a changed manifest or lockfile in a project that the filtered install left out, including the workspace root after a filtered install with `pruneDirectDependencies: true` [pnpm/tasks#181](https://github.com/pnpm/tasks/issues/181). A filtered install also preserves the recorded ignored build scripts of unselected projects, and `pnpm dedupe --check` and `pnpm install --dry-run` no longer record outdated dependencies as installed. - The `verifyDepsBeforeRun` check now holds the workspace projects that the selected project depends on, including `link:` workspace dependencies. `--filter=<project>...` now selects `link:` dependencies as well. With `sharedWorkspaceLockfile: false`, `verifyDepsBeforeRun` also reports dependencies as outdated when a selected project's `pnpm-lock.yaml` is missing [pnpm/tasks#138](https://github.com/pnpm/tasks/issues/138). - `verifyDepsBeforeRun` and repeat `pnpm install` runs now apply `overrides` before comparing a modified `package.json` with `pnpm-lock.yaml` [#&#8203;17127](https://github.com/pnpm/pnpm/issues/17127). `verifyDepsBeforeRun` also checks whether each importer's resolved catalog versions match the catalog snapshot in `pnpm-lock.yaml`, and respects `lockfileDir` in single-project repositories. - `verifyDepsBeforeRun` now compares manifests, lockfiles, and patch files by content hash. It notices an edit that kept the file's modification time, as `cp -p`, `rsync -a`, or an archive extraction leave it, and a patch file that was copied or touched without changing its content no longer marks dependencies as outdated [#&#8203;16988](https://github.com/pnpm/pnpm/issues/16988). ##### Deploying and other commands - `pnpm deploy` now records the peer dependencies of the workspace packages it copies into the deployed lockfile. Before, pnpm rejected that lockfile with `--frozen-lockfile` when a deployed workspace package declared a peer and `injectWorkspacePackages` was off [#&#8203;17093](https://github.com/pnpm/pnpm/issues/17093). - `pnpm install --frozen-lockfile` and `verifyDepsBeforeRun` now succeed inside a directory created by `pnpm deploy`. `pnpm deploy` writes self-contained workspace and lockfile settings, prunes unused `patchedDependencies`, and preserves workspace-level dependency resolutions on deployed directory dependencies. - In workspaces with `sharedWorkspaceLockfile: false`, `pnpm patch`, `pnpm patch-commit`, and `pnpm patch-remove` now resolve patch files and `patchedDependencies` entries at the workspace root. `pnpm install` checks configured patches across all workspace projects before reporting unused patches. - Trusted publishing with OIDC now works with registries whose URL has a path, such as `https://registry.example/npm/private/`. pnpm previously sent the token exchange request to the root of the registry host. - `pnpm owner ls` now lists the owners of a package on the npm registry. It reported every package as not found. - `pnpm sbom` now reads project lockfiles in workspaces with `sharedWorkspaceLockfile: false`, including filtered and split output, and reports the repository of a package whose `repository` field is a `gist:` shorthand. - `pnpm licenses list` reports no licenses for workspace projects not recorded in the lockfile. It errors when `pnpm-lock.yaml` is missing. Empty results now use the requested text or JSON format [pnpm/tasks#174](https://github.com/pnpm/tasks/issues/174). - `pnpm why` now reads each selected workspace project's lockfile and modules directory when `sharedWorkspaceLockfile` is `false` [pnpm/tasks#169](https://github.com/pnpm/tasks/issues/169). - `pnpm pkg fix` now converts a `repository` string such as `github:pnpm/example` to the object form, as `npm pkg fix` does. It also normalizes a GitHub, GitLab, or Bitbucket repository URL the way `npm pkg fix` does [#&#8203;16980](https://github.com/pnpm/pnpm/issues/16980). ##### Configuration and setting up pnpm - pnpm now recognizes `externalDependencies` and `autoInstallPeersFromHighestMatch` in `pnpm-workspace.yaml` without warning and forwards both settings to `pnpm install`. Previously, setting `externalDependencies` in `pnpm-workspace.yaml` with `nodeLinker: hoisted` crashed `pnpm install` with `externalDependencies.has is not a function` [pnpm/tasks#166](https://github.com/pnpm/tasks/issues/166). - pnpm now ignores a `PNPM_CONFIG_*` environment variable for a URL setting, such as `PNPM_CONFIG_REGISTRY`, when its value is not a URL. Such a value used to make every command fail with `Invalid URL`. - The warning about unrecognized settings in `pnpm-workspace.yaml` and the global `config.yaml` now names `addMissingPeerTypes`, `autoDedupe`, `bootConfig`, `macosBackup`, `nodePackageMap`, `permissions`, `pipelineBase`, `publishWaitTimeout`, `python`, `remoteCache`, `saveTypes`, `skills`, `storeIndexFormat`, and `tools` as pnpm v12 settings [pnpm/tasks#167](https://github.com/pnpm/tasks/issues/167). - When a config file has a setting pnpm cannot read, `pnpm --version` now prints the version, and `pmOnFail` and `lockfileDir` in `pnpm-workspace.yaml` stay in force. Previously, pnpm switched to the pinned version despite `pmOnFail: ignore`. pnpm also no longer writes the pinned version to `pnpm-lock.yaml` when it cannot read every setting and the running pnpm already matches the pin. - pnpm now records the pinned pnpm version in the `pnpm-lock.yaml` under the `lockfileDir` set in `pnpm-workspace.yaml`, and resolves a relative `lockfileDir` from the workspace root. pnpm used to write a second `pnpm-lock.yaml` at the workspace root. - `pnpm self-update` now updates the project's pnpm pin when Homebrew installed pnpm or Corepack runs it. The global pnpm is left alone [#&#8203;17001](https://github.com/pnpm/pnpm/issues/17001). - `pnpm setup` now completes when Windows registry environment values cannot be read or written. It prints PowerShell commands to configure `PNPM_HOME` and `PATH` without registry access [#&#8203;17167](https://github.com/pnpm/pnpm/issues/17167). - `pnpm setup` now succeeds when it cannot tell which shell configuration file to update, for example in a container where `SHELL` is not set. It installs pnpm and prints the `PNPM_HOME` and `PATH` lines to add yourself. Previously it failed with `ERR_PNPM_UNKNOWN_SHELL`, and so did the installer script at get.pnpm.io [#&#8203;16973](https://github.com/pnpm/pnpm/issues/16973). <!-- 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 --> ### [`v11.28.6`](https://github.com/pnpm/pnpm/releases/tag/v11.28.6): pnpm 11.28.6 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.5...v11.28.6) This release stops `pnpm publish` from sending a CI identity token to a registry it was not issued for. It also fixes installs that dropped a dependency also declared as an optional peer, and accepts empty `httpProxy` and `httpsProxy` settings again. ##### Patch Changes ##### Security - `pnpm publish` now uses an `NPM_ID_TOKEN` only if its `aud` claim matches the selected registry, such as `npm:registry.npmjs.org`. A token for another registry is skipped with a warning, and pnpm falls back to the configured credentials. - The warning about renamed package files with invalid names no longer prints control characters from those file names. ##### Configuration - pnpm again accepts `httpProxy` and `httpsProxy` set to `null` or written with no value in `pnpm-workspace.yaml` and the global config file, and treats them as unset. Since 11.28.5 these values failed with `ERR_PNPM_INVALID_SETTING`. - pnpm now switches to the pnpm version a project pins even when it cannot read its configuration. Previously, a setting it rejected in the global config file, an `.npmrc` file, `_auth`, or `pnpm-workspace.yaml` stopped every command, `pnpm --version` included. - A key under a registry URL in the `_auth` setting that does not start with `@` is now skipped with a warning, so a field a later pnpm version adds there no longer breaks this one. A key that holds an `authToken` object but lacks its `@`, such as `org` for `@org`, is still an error. ##### Resolving dependencies - pnpm no longer drops a dependency that a package also declares as an optional peer dependency, for example `ajv` of `ajv-formats`. Since 11.28.0, in some dependency graphs the package got the dependency neither as a dependency nor as a peer, and failed to import it [#&#8203;16901](https://github.com/pnpm/pnpm/issues/16901). - `pnpm install` no longer fails with `ERR_PNPM_NO_MATCHING_VERSION` after a change to `overrides` when the lockfile resolves an optional peer dependency to an npm alias of another package [#&#8203;16654](https://github.com/pnpm/pnpm/issues/16654). - `pnpm install` and `pnpm dedupe` now link an optional peer to the workspace package that the workspace root depends on when the picked version matches it. Previously they installed the registry package with the same name and version [#&#8203;16706](https://github.com/pnpm/pnpm/issues/16706). - Removal overrides such as `"debug>supports-color": "-"` now also apply to an optional peer that a package declares only in `peerDependenciesMeta` [#&#8203;16681](https://github.com/pnpm/pnpm/issues/16681). - `pnpm dedupe` now preserves a hoisted workspace package when another package uses a separately installed peer with the same name [#&#8203;16935](https://github.com/pnpm/pnpm/issues/16935). - `pnpm install` and `pnpm add --config` now apply `minimumReleaseAge` when they resolve a config dependency. A config dependency range resolves to the newest version that is old enough, so a later clean `pnpm install --frozen-lockfile` accepts the lockfile [#&#8203;16660](https://github.com/pnpm/pnpm/issues/16660). - `pnpm install --fix-lockfile` no longer removes the `deprecated` and `hasBin` fields from lockfile entries [#&#8203;6600](https://github.com/pnpm/pnpm/issues/6600). ##### Workspaces and catalogs - A filtered install, such as `pnpm install --filter <pkg>`, now keeps the `pnpm-lock.yaml` entries of workspace projects that are missing from disk, as in a sparse checkout. Their importers, packages, and catalog entries stay even when the filter matches every project on disk [#&#8203;16931](https://github.com/pnpm/pnpm/issues/16931). - `catalogPrune` no longer removes catalog entries that `pnpm-lock.yaml` still records for workspace projects missing from disk. This affected `pnpm remove` and installs that leave the lockfile unchanged, such as frozen installs. Before, a following frozen install failed with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` [#&#8203;16679](https://github.com/pnpm/pnpm/issues/16679). - Sped up workspace discovery with subtree exclusions such as `!generated/**`. ##### Linking node_modules - `pnpm install` no longer fails on Windows with `EPERM` on `rmdir node_modules/@scope` when several workspace packages under one scope are hoisted, for example with `nodeLinker: hoisted` [#&#8203;16690](https://github.com/pnpm/pnpm/issues/16690). - `pnpm install` hardlinks files from a group-writable or world-writable store again. Before this fix, pnpm copied every file from such a store into `node_modules` [#&#8203;16677](https://github.com/pnpm/pnpm/issues/16677). - With `enableGlobalVirtualStore`, an install that updates `node_modules` now restores the dependency links of a package in the global virtual store that an interrupted install left without them. Before, such an install kept the incomplete package if the project's `node_modules` already recorded it [#&#8203;16642](https://github.com/pnpm/pnpm/issues/16642). - Removing a `link:` dependency now also removes its symlink from `node_modules` when `nodeLinker` is `hoisted` [#&#8203;16884](https://github.com/pnpm/pnpm/issues/16884). - An install that adds nothing to the store no longer changes the modification time of the store directory. CI caches that check modification times, such as GitLab's, no longer re-upload an unchanged store [#&#8203;16929](https://github.com/pnpm/pnpm/issues/16929). ##### Injected workspace packages - With `sharedWorkspaceLockfile: false`, an injected workspace package installed in the same run as its dependent now holds only the files its `files` field selects. The copy used to also hold other files of the project, such as `tsconfig.json` [#&#8203;16683](https://github.com/pnpm/pnpm/issues/16683). - A script listed in `syncInjectedDepsAfterScripts` no longer fails when it rewrites `package.json` while pnpm is copying its edits into the injected copies. The sync after the script now replaces a half-copied manifest. - Sped up frozen installs of unchanged injected workspace packages that use hardlinks. ##### Deploying - `pnpm deploy` without `injectWorkspacePackages` now binds a peer dependency of a linked workspace package to the version its parent provides, as an injected install does. Previously the deploy failed with `ERR_PNPM_DEPLOY_AMBIGUOUS_PEER` whenever other packages in the deployed graph depended on different versions of that peer [#&#8203;16807](https://github.com/pnpm/pnpm/issues/16807). - `pnpm deploy` in a workspace with `injectWorkspacePackages` no longer crashes when a linked workspace package declares a peer dependency named after an `Object.prototype` member, such as `constructor`. ##### Setting up pnpm - pnpm now relinks the bins of a pnpm version it installed earlier for `packageManager` or `pnpm with`. A pnpm 12 version installed by a pnpm release older than 11.28.4 could keep a launcher that ran `node` on the native binary, so every command failed with `SyntaxError: Invalid or unexpected token` [#&#8203;16646](https://github.com/pnpm/pnpm/issues/16646). - `pnpm setup` no longer tries to install pnpm globally from npm's `bin` directory when pnpm was installed with npm. It printed `Failed to create bin at <PNPM_HOME>/bin/pnpm` [#&#8203;16855](https://github.com/pnpm/pnpm/issues/16855). ##### Output - Escape codes in script output that moved the cursor or cleared the screen garbled pnpm's output. pnpm now drops them and keeps only color codes. Color codes are dropped too when pnpm's own output is not in color. - When the registry rejects `pnpm stage publish`, the error message now starts with "Failed to stage package". <!-- 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 --> ### [`v11.28.5`](https://github.com/pnpm/pnpm/releases/tag/v11.28.5): pnpm 11.28.5 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.4...v11.28.5) This release reads cached registry metadata faster and makes `pnpm config get --global` ignore project settings. It also carries several security fixes for package archives, git dependencies, and config dependencies. ##### Patch Changes ##### Security - pnpm now verifies locked config dependencies against their registry before installing them. Config dependencies must come from an npm registry. The lockfile can no longer replace the integrity of a config dependency pinned with `version+integrity`. - Lockfile verification now checks the tarballs inside a `variations` resolution against the registry. A `name@version` lockfile entry with an empty `variations` resolution is now rejected. - `pnpm audit signatures` now verifies signatures against the integrity recorded in the lockfile. Packages without a recorded integrity cannot pass signature verification. - pnpm now rejects a git dependency whose lockfile repository is empty, begins with `-`, or contains a null byte. Git can no longer read such a value as a command-line option [pnpm/tasks#84](https://github.com/pnpm/tasks/issues/84). - A git dependency with a `#path:` subpath can no longer reach files outside the repository through a symlink in the subpath. - `pnpm pack`, `pnpm publish`, and installs of git and local directory dependencies now leave out files that a directory symlink or a `bundleDependencies` entry points to outside the package directory [pnpm/tasks#83](https://github.com/pnpm/tasks/issues/83) [pnpm/tasks#93](https://github.com/pnpm/tasks/issues/93). - `pnpm deploy` with `deployAllFiles` now rejects symlinks that point outside the package directory. Local package installs with this setting apply the same check. - pnpm no longer hangs on a package archive with a negative PAX record length or an entry of 4 GiB or more [pnpm/tasks#78](https://github.com/pnpm/tasks/issues/78) [pnpm/tasks#79](https://github.com/pnpm/tasks/issues/79). - Large package downloads and large files inside gzip and bzip2 package archives now use bounded memory during installation. Package manifests and archive metadata larger than 64 MiB are rejected. `pnpm publish` also rejects manifests and README files larger than 64 MiB in pre-built tarballs before reading them into memory. - Two URL or local path dependencies no longer share a virtual store directory when one URL has `+`, `#`, `:`, or `?` where the other has `/`. Such dependencies, including git dependencies pinned with `#`, now get a hash suffix on their directory name. - `pnpm licenses` now removes terminal control characters from package metadata in table output. - The warnings about ignored project `.npmrc` registry and auth settings no longer print the username and password of a URL-scoped key such as `//user:password@registry.example.com/:_authToken`. ##### Installing and resolving dependencies - Dependency resolution reads cached registry metadata faster. The metadata cache moved to `<cache-dir>/v12/`, so the first install after upgrading downloads registry metadata again. A damaged cache entry is downloaded again, or reported as an error when `--offline` is set [#&#8203;13512](https://github.com/pnpm/pnpm/pull/13512). - `pnpm install` now fails with `ERR_PNPM_UNSUPPORTED_PROTOCOL` when a dependency uses a specifier with a protocol pnpm does not support, such as Yarn's `patch:`. pnpm linked such a dependency to a directory that does not exist [#&#8203;16590](https://github.com/pnpm/pnpm/issues/16590). - When a dependency moves an exact dependency of its own to an older version, a peer dependency that pnpm installed automatically now moves with it. Before, `pnpm install` and `pnpm dedupe` kept the newer locked version of the peer, so the lockfile held two copies of it, for example two copies of `vue` [pnpm/tasks#61](https://github.com/pnpm/tasks/issues/61). - `pnpm add` and `pnpm install` now keep the peer dependencies that `pnpm-lock.yaml` records for a package they did not update. A registry whose metadata disagrees with the package's `package.json`, for example by omitting `peerDependenciesMeta`, made `pnpm add` and `pnpm dedupe` write different lockfiles, so `pnpm dedupe --check` failed after `pnpm add` [#&#8203;16615](https://github.com/pnpm/pnpm/issues/16615). ##### Configuration - `pnpm config get` and `pnpm config list` with `--global` or `--location=global` now show only the global configuration. Both flags included the project's `.npmrc` before. `--location=global` also included the project's `pnpm-workspace.yaml`. `pnpm config get --global` failed when the global bin directory was not in PATH [#&#8203;16598](https://github.com/pnpm/pnpm/issues/16598). - pnpm now prints config warnings, such as an unset environment variable in `.npmrc`, when loading the config fails. - pnpm now fails when `httpProxy` or `httpsProxy` in `pnpm-workspace.yaml` or the global configuration is not a string. - `pnpm dlx` now uses the `release` entry of `nodeDownloadMirrors` from the workspace configuration when downloading Node.js runtimes [#&#8203;11281](https://github.com/pnpm/pnpm/issues/11281). Mirrors for other channels, such as `rc` and `nightly`, still apply only from the global configuration. ##### Commands - `pnpm run` and `pnpm exec` now forward `--config.*` command-line flags to the install started by `verifyDepsBeforeRun` [pnpm/tasks#60](https://github.com/pnpm/tasks/issues/60). - `pnpm dlx` with `--package` but no command now fails with `'pnpm dlx' requires a command to run`. Before, it installed the package and then crashed trying to run an empty command. - `pnpm unpublish <pkg>@<version>` now deletes the tarball under the registry's path when the registry is served under one, such as Gitea's npm registry. It used to send the delete to the host root and report success without removing the version [#&#8203;16568](https://github.com/pnpm/pnpm/issues/16568). It also no longer mistakes a sibling path such as `/npm-mirror/` for the registry path `/npm/` [pnpm/tasks#94](https://github.com/pnpm/tasks/issues/94). - The interactive `pnpm audit --fix` picker now shows each patched version with the `saveExact` and `savePrefix` style that the override is written with [#&#8203;13209](https://github.com/pnpm/pnpm/issues/13209). - `pnpm list` now reports the correct package paths when `nodeLinker` is `hoisted` [#&#8203;9593](https://github.com/pnpm/pnpm/issues/9593). - `pnpm setup` now puts `$PNPM_HOME/bin` first on `PATH` in login shells that inherited it further down, such as the VS Code terminal on macOS. Before, another `node` took precedence over the one installed by `pnpm runtime set node -g`. Run `pnpm setup` again to update the block in your shell config [#&#8203;16635](https://github.com/pnpm/pnpm/issues/16635). - `pnpm setup` now names the shell config file even if it is already up to date [#&#8203;16608](https://github.com/pnpm/pnpm/issues/16608). ##### Output and messages - A warning about a project's `devEngines` or `packageManager` pin is now printed to stderr. A command such as `pnpm cache path` or `pnpm list --json` keeps only its own output on stdout [#&#8203;16584](https://github.com/pnpm/pnpm/issues/16584). - The warning for a non-root `resolutions` field now points at the `overrides` field in `pnpm-workspace.yaml` [#&#8203;11757](https://github.com/pnpm/pnpm/issues/11757). <!-- 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 --> ### [`v11.28.4`](https://github.com/pnpm/pnpm/releases/tag/v11.28.4): pnpm 11.28.4 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.3...v11.28.4) pnpm 11.28.4 fixes two ways credentials could leak, makes `pnpm install --frozen-lockfile` accept several lockfiles it rejected, warns when an optional dependency cannot be fetched, and stops `pnpm self-update` from installing a second pnpm next to a Homebrew one. ##### Patch Changes - `pnpm login` no longer forwards credentials in its request body to another origin during redirects. - The error for a tarball that fails its integrity check no longer prints credentials, query strings, or fragments from the tarball URL. ##### Installing packages - `pnpm install --frozen-lockfile` now succeeds in a project with no dependencies when `pnpm-lock.yaml` records only the pinned pnpm version. Other commands write such a lockfile when they run before the first install. A lockfile missing the `---` line after that section is accepted too [#&#8203;16477](https://github.com/pnpm/pnpm/issues/16477). - `pnpm install --frozen-lockfile` again succeeds when a workspace project recorded in `pnpm-lock.yaml` has no directory, such as a project left out of a Docker build context. It still fails if the project's directory exists without a `package.json` [#&#8203;16453](https://github.com/pnpm/pnpm/issues/16453). - `pnpm install --frozen-lockfile` no longer fails with `ERR_PNPM_OUTDATED_LOCKFILE` for a workspace project that declares `dependenciesMeta` and whose dependencies are all workspace links. pnpm now records that project's `dependenciesMeta` in `pnpm-lock.yaml` [#&#8203;16457](https://github.com/pnpm/pnpm/issues/16457). - Fixed frozen installs replacing a hoisted dependency with a workspace package of the same name. A later `pnpm dedupe` then removed the hoisted link [#&#8203;16485](https://github.com/pnpm/pnpm/issues/16485). - With `enableGlobalVirtualStore` on, scripts can run entry points that a CommonJS require hook loads again, such as `ts-node index.ts`. They failed with `ERR_UNKNOWN_FILE_EXTENSION` on Node.js versions without built-in TypeScript support [#&#8203;16436](https://github.com/pnpm/pnpm/issues/16436). ##### Optional dependencies - `pnpm install` now prints a warning with the error when an optional dependency cannot be fetched and is skipped. The skipped package is no longer linked into `node_modules` as a broken symlink or listed among the added dependencies. The `pnpm:skipped-optional-dependency` log reports the skip with the `fetch_failure` reason [#&#8203;16514](https://github.com/pnpm/pnpm/issues/16514). - When an optional dependency fails to build, pnpm now removes its link from `node_modules`. A repeat `pnpm install` then reports "Already up to date" and no longer reruns the failing build [#&#8203;16468](https://github.com/pnpm/pnpm/issues/16468). - Fixed frozen installs creating symlinks to the working directory for skipped optional dependencies and unresolved peer dependencies [#&#8203;16454](https://github.com/pnpm/pnpm/issues/16454). ##### Hoisted node_modules - With `nodeLinker: hoisted`, a filtered install now keeps the packages of the workspace projects an earlier install put in `node_modules`. This also covers the install that `pnpm --filter <selector> run` and `pnpm --filter <selector> exec` start before the command. Before, these installs removed every package that only the unselected projects needed [#&#8203;16483](https://github.com/pnpm/pnpm/issues/16483). A filtered install of a workspace project also no longer fails with `ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY` after a filtered install of another project. - `pnpm install` with `nodeLinker: hoisted` now refreshes directories supplied by custom fetchers when reinstalling. ##### Speed and network - pnpm now revalidates cached registry metadata with a conditional request, so the registry can answer `304 Not Modified`. Before, pnpm downloaded the whole document again for registries whose responses forbid caching, such as `Cache-Control: no-store` [#&#8203;16528](https://github.com/pnpm/pnpm/issues/16528), and for packages published within `minimumReleaseAge` [#&#8203;16506](https://github.com/pnpm/pnpm/issues/16506). - A fetch timeout while other downloads from the same host are still running now lowers concurrency for that host to one connection. Retries of that request, and later downloads from that host, use the lower concurrency. Other hosts keep the configured concurrency [#&#8203;12791](https://github.com/pnpm/pnpm/issues/12791). ##### Running scripts - Scripts run without a terminal no longer start a second `sh` each. One watchdog per pnpm command now ends every script's process group if pnpm is killed, so `pnpm -r run` across many projects starts half as many processes [#&#8203;16489](https://github.com/pnpm/pnpm/issues/16489). - `pnpm run` and `pnpm exec` now warn and run the command when the install that `verifyDepsBeforeRun` starts fails. This lets scripts run in sandboxes where pnpm cannot install, such as containers with a read-only store or no network [#&#8203;15173](https://github.com/pnpm/pnpm/issues/15173). - A filtered `pnpm run` or `pnpm exec` now finds dependencies out of date when a workspace dependency of a selected project has no `node_modules` directory, as after a filtered install. With `verifyDepsBeforeRun: install`, pnpm installs that dependency before running the command [pnpm/tasks#45](https://github.com/pnpm/tasks/issues/45). - `pnpm rebuild` and `pnpm approve-builds` refresh command launchers when a build changes a command's interpreter or replaces it with a native executable. Dependent packages' build scripts use the refreshed launchers. ##### Updating pnpm - `pnpm self-update` now fails for Homebrew-installed pnpm and prints the `brew upgrade` command for the installed formula, such as `brew upgrade pnpm` or `brew upgrade pnpm@11`. It used to install a second copy of pnpm that the Homebrew one kept shadowing [#&#8203;16547](https://github.com/pnpm/pnpm/issues/16547). - On Windows, `pnpm self-update` now replaces a `pnpm.exe` left in `PNPM_HOME` or in `PNPM_HOME\bin`. In `PNPM_HOME`, that executable kept running the old version after a successful update. In `PNPM_HOME\bin`, the update failed with `EPERM`. If the executable was in `PNPM_HOME`, `self-update` now asks you to run `pnpm setup` [#&#8203;9094](https://github.com/pnpm/pnpm/issues/9094). - pnpm can now switch to a `packageManager` version below 11 on x64 musl Linux, such as Alpine [#&#8203;16467](https://github.com/pnpm/pnpm/issues/16467). - A `devEngines.packageManager` range now records the running pnpm in `pnpm-lock.yaml` only if it meets `minimumReleaseAge`. Otherwise pnpm records the newest version in the range that meets it. If no version in the range does, pnpm still records the running pnpm [#&#8203;16431](https://github.com/pnpm/pnpm/issues/16431). ##### Filtering, settings, and other commands - The `[<since>]` filter selector works again with Git 2.24 through 2.27 [#&#8203;16561](https://github.com/pnpm/pnpm/issues/16561). With Git older than 2.24, the selector now fails with an error that names the required Git version. - Package-name filters now support `?` to match one character [#&#8203;2817](https://github.com/pnpm/pnpm/issues/2817). - `pnpm -r pkg get` now reports every selected project when several share a package name. Projects with the same name are keyed by their directory relative to the workspace root. Before, only one of them appeared in the output. - pnpm now reports an `INVALID_SETTING` error when `allowUnusedPatches` in `pnpm-workspace.yaml` is not a boolean, or when `ignoredOptionalDependencies` or `requiredScripts` is not an array of strings. A quoted `allowUnusedPatches` value such as `"false"` was treated as `true`. - `pnpm store path`, `pnpm store status`, and other commands that look up the default store no longer fail when the current directory is not writable. pnpm now uses the store in the pnpm home directory in that case [#&#8203;16554](https://github.com/pnpm/pnpm/issues/16554). <!-- 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 --> ### [`v11.28.3`](https://github.com/pnpm/pnpm/releases/tag/v11.28.3): pnpm 11.28.3 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.2...v11.28.3) pnpm 11.28.3 updates `undici` to clear a security advisory, fixes "database disk image is malformed" errors when several pnpm processes share a store, and makes packages, catalogs, projects, and commands named like `constructor` work. ##### Patch Changes ##### Installing packages - pnpm now ships `undici` 7.29.1, so security scans of pnpm no longer report [GHSA-3wwx-pv8p-q78v](https://github.com/advisories/GHSA-3wwx-pv8p-q78v). - pnpm no longer fails with "database disk image is malformed" or reads stale store entries while another pnpm process writes to the same store. - Names that match built-in JavaScript object properties, such as `constructor`, `toString`, or `__proto__`, now work like any other name. pnpm crashed, wrote a wrong lockfile, or silently skipped such names in: - `pnpm add`, `pnpm install`, and `pnpm import`, for dependencies, peer dependencies, and `file:` dependencies that point to a directory named `constructor`. - Catalog entries and catalog names. Pruning unused entries crashed, and a new catalog named `toString` was not written. - Workspace projects, project directories, and files inside injected packages. - Registry prefixes and override version references such as `$toString`. - Hoisting, `pnpm list`, and `pnpm why`. - Command names. `pnpm constructor` runs the `constructor` script like any other unknown command, and `pnpm help constructor` no longer crashes. - Resolving through a pnpr server when a project lives in a directory named `constructor`. - `pnpm install` no longer re-resolves an up-to-date lockfile on every run when a patched package is a peer in a peer cycle [#&#8203;16418](https://github.com/pnpm/pnpm/issues/16418). - POSIX bin shims and the `pnpm`, `pn`, `pnpx`, and `pnx` launchers now run inside a Nix build, where the system default path holds none of the utilities they call. Installing again replaces the shims already in `node_modules` [#&#8203;16377](https://github.com/pnpm/pnpm/issues/16377). - In a project that pins another pnpm version, pnpm now passes a command with an option it does not know to the pinned version. Before, `pnpm install --auto-dedupe` failed with "Unknown option" even though the pinned pnpm supports it [#&#8203;16353](https://github.com/pnpm/pnpm/issues/16353). - pnpm now fails with `ERR_PNPM_INVALID_ALLOW_BUILDS` when `allowBuilds` is not an object or one of its values is not `true`, `false`, or a string. Such values used to be ignored silently. - Removing a dependency whose bins are declared through `directories.bin` no longer leaves broken shims in `node_modules/.bin`. - A custom resolver's `shouldRefreshResolution` hook that rejects no longer crashes pnpm with an unhandled rejection when another hook has already asked for a refresh. ##### Updating dependencies - When `minimumReleaseAge` hides the version that `latest` points to, pnpm now falls back to a prerelease of the same major before a stable version of an older major. A stable version of the same major is still preferred. For example, while a new `1.0.0` is too new, pnpm picks `1.0.0-beta.4` rather than an old `0.0.1` [#&#8203;16388](https://github.com/pnpm/pnpm/issues/16388). - `pnpm --filter <project> update <pkg>` now fails with `ERR_PNPM_NO_PACKAGE_IN_DEPENDENCIES` when the selected projects do not depend on `<pkg>`, also in a workspace with a shared lockfile and a root project. It used to exit successfully. - `pnpm audit --fix` now updates vulnerable packages in a single project that sets `updateConfig.ignoreDependencies`. It used to leave them on the vulnerable version. - `pnpm update --global` now removes hard-linked executables from `PNPM_HOME` when migrating packages from the old global layout [#&#8203;16420](https://github.com/pnpm/pnpm/issues/16420). - Updating a pinned GitHub Action now rewrites the version in its `# vX.Y.Z` comment even when the action name contains the same version text. The action name used to change while the comment kept the old version. ##### Workspaces and deploy - `pnpm deploy` no longer fails with `ERR_PNPM_DEPLOY_AMBIGUOUS_PEER` in a workspace with `injectWorkspacePackages: true` when a workspace package also lists its peer dependency as a dev dependency [#&#8203;16375](https://github.com/pnpm/pnpm/issues/16375). - `pnpm deploy` no longer copies the workspace root's `packageManager` and `devEngines.packageManager` fields into the deployed `package.json` [#&#8203;16403](https://github.com/pnpm/pnpm/issues/16403). - `--filter` fixes: - A `...pkg...` selector combined with another dependents selector, such as `--filter ...a --filter ...b...`, no longer adds the dependencies of the other selector's dependents. - `--filter "[<since>]"` now detects changes in projects whose directory names contain non-ASCII characters. The change used to be credited to the parent project. ##### Running scripts - After relaying a signal to a script, pnpm keeps waiting for a process in the script's process group whose main thread has exited while its other threads still run. Linux reports such a process as a zombie, so the wait used to end before those threads finished [pnpm/tasks#56](https://github.com/pnpm/tasks/issues/56). - A lifecycle script run with `unsafePerm: false` now fails with an error when pnpm cannot create `node_modules/.tmp`. It used to hang. - `pnpm run` with `verifyDepsBeforeRun` no longer crashes with an unhandled rejection when a lockfile it did not need to compare fails to load. - `pnpm run -r` now closes the collapsible CI log section of a project whose script fails, so the output of later projects is no longer nested inside it. - `pnpm run --resume-from` no longer crashes when a saved run state file contains `null`. ##### Store - `pnpm store prune` now removes the packages that only expired `pnpm dlx` cache entries used, as long as the store still has another registered project. They used to stay until the next `pnpm store prune` [#&#8203;16383](https://github.com/pnpm/pnpm/discussions/16383). - `pnpm store prune` now stops with an error when it cannot read a project directory for a reason other than the directory missing, such as a permission error. It used to skip the directory. ##### Publishing and registry output - `pnpm publish` now includes bare `README` files and README files with Markdown extensions such as `readme.markdown` in registry metadata [#&#8203;12704](https://github.com/pnpm/pnpm/issues/12704). - `pnpm pack-app` now accepts an entry file or output directory inside the project whose name starts with two dots, such as `..build/entry.cjs`. It used to fail with `ERR_PNPM_PACK_APP_ENTRY_OUTSIDE_PROJECT`. - Registry error messages now always say "(response body truncated)" when pnpm cut the response body short. The marker was missing when the body was cut at exactly 64 KiB. <!-- 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 --> ### [`v11.28.2`](https://github.com/pnpm/pnpm/releases/tag/v11.28.2): pnpm 11.28.2 [Compare Source](https://github.com/pnpm/pnpm/compare/pnpm@11.28.1...v11.28.2) pnpm 11.28.2 fixes `pnpm install` skipping every workspace project whose common ancestor is the filesystem root, and stops `pnpm run` from reinstalling or installing when nothing needs it. ##### Patch Changes - `pnpm install` reported success without installing anything when the workspace projects' common ancestor was the filesystem root, such as `/` or a drive root like `C:\`. It now installs these projects [#&#8203;16328](https://github.com/pnpm/pnpm/issues/16328). - `verifyDepsBeforeRun` no longer reports dependencies as outdated after a filtered install just because `pnpm-lock.yaml` has a newer modification time. It checks the lockfile against the packages that install put in place. Before, `pnpm run` reinstalled the whole workspace with lifecycle scripts on, for example after a Docker `COPY` brought in a lockfile with a newer mtime [#&#8203;16322](https://github.com/pnpm/pnpm/issues/16322). After a filtered install, `verifyDepsBeforeRun` now also checks that the install put the selected projects' dependencies in place. A `node_modules` directory alone no longer counts as proof. - `pnpm run` and `pnpm exec` no longer install a project that has never been installed and has nothing to install. Such a project declares no dependencies, no peer dependencies that `autoInstallPeers` would fetch, and no install lifecycle scripts. The command now runs without writing `node_modules` or `pnpm-lock.yaml` [#&#8203;16313](https://github.com/pnpm/pnpm/issues/16313). <!-- 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 --> ### [`v11.28.1`](https://github.com/pnpm/pnpm/releases/tag/v11.28.1): pnpm 11.28.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.28.0...pnpm@11.28.1) pnpm 11.28.1 makes `pnpm install` work in StackBlitz WebContainers, repairs lockfiles whose patch hashes disagree with `patchedDependencies`, and fixes many bugs in Windows command shims, injected workspace dependencies, and `pnpm deploy`. ##### Patch Changes ##### Installing packages - `pnpm install` now works in StackBlitz WebContainers. On projects without a lockfile, it used to fail with `ENOENT ... pnpm-lock.yaml`, because pnpm did not recognize the errors that WebContainers return from asynchronous file system calls. It also failed with "this.db.exec is not a function", because `node:sqlite` there lacks `DatabaseSync.exec`. When `node:sqlite` cannot prepare statements either, pnpm stores the index in `index.fallback` [#&#8203;15649](https://github.com/pnpm/pnpm/issues/15649). - `pnpm install` now completes after downloading a Node.js runtime specified by `devEngines.runtime` when pnpm runs on Node.js 24.4.x [#&#8203;14667](https://github.com/pnpm/pnpm/issues/14667). - `pnpm install` no longer fails when a package from the registry declares a `file:` dependency on a directory inside itself, such as `"@types/css-tree": "file:./typings/css-tree"`. pnpm links that dependency to the directory inside the package, as npm and Yarn do. The lockfile records it as `link:<root>/typings/css-tree` [#&#8203;9141](https://github.com/pnpm/pnpm/issues/9141). - Installing a git-hosted dependency that has to be built no longer fails when that dependency's own dependencies have build scripts nobody approved. pnpm skips those builds while preparing the dependency, as it does without `strictDepBuilds` [#&#8203;9764](https://github.com/pnpm/pnpm/issues/9764). - pnpm now uses pnpm to prepare a git-hosted dependency that is a pnpm workspace without a committed lockfile. It used npm before, which could skip the dependency's build [#&#8203;14011](https://github.com/pnpm/pnpm/issues/14011). - When installing a git dependency over SSH fails with `Permission denied (publickey)`, pnpm suggests checking the loaded keys with `ssh-add -l`. Resolving an SSH URL that refuses the key also shows a local HTTPS rewrite that leaves the recorded URL alone [#&#8203;13743](https://github.com/pnpm/pnpm/issues/13743). - `pnpm install --dev` and `pnpm fetch --dev` now install the optional dependencies of devDependencies, such as the platform binaries of Biome and oxlint. The project's own `optionalDependencies` are still skipped [#&#8203;9678](https://github.com/pnpm/pnpm/issues/9678). - `pnpm install --frozen-lockfile` now works on a detached HEAD when `gitBranchLockfile` is enabled. The install now reads the lockfiles of the local and remote-tracking branches that contain the checked-out commit. It still writes the shared `pnpm-lock.yaml` [#&#8203;7672](https://github.com/pnpm/pnpm/issues/7672). - `pnpm install` on CI now fails on an outdated lockfile when `preferFrozenLockfile` is explicitly set to `true`. Setting it to `true` used to let CI update the lockfile [#&#8203;9072](https://github.com/pnpm/pnpm/pull/9072). - `pnpm install` now fails with `ERR_PNPM_IGNORED_BUILDS` on a repeat install when `strictDepBuilds` is on and a dependency's build is still undecided. A repeat install against an existing `node_modules` reported success where a fresh install failed [#&#8203;10450](https://github.com/pnpm/pnpm/issues/10450). - `pnpm install` now removes an optional dependency from `node_modules` if its install script fails. Code that checks whether the package is installed no longer finds a package that cannot load [#&#8203;8756](https://github.com/pnpm/pnpm/issues/8756). - `pnpm install --offline` and `pnpm add --offline` now resolve a version range to the newest matching version whose tarball is already in the store. They used to pick the newest version in the cached metadata and fail with `ERR_PNPM_NO_OFFLINE_TARBALL` when its tarball was missing [#&#8203;10715](https://github.com/pnpm/pnpm/issues/10715). - If an offline install fails because the registry metadata cache uses the layout from before pnpm 11.27 and 12.4, the error now names the older mirror on disk and explains that one online install repopulates the cache [#&#8203;15656](https://github.com/pnpm/pnpm/issues/15656). - `pnpm install` now fails right away when writing package files fails because the store is full. It no longer retries the tarball download first [#&#8203;8581](https://github.com/pnpm/pnpm/issues/8581). - With `nodeLinker: hoisted`, `pnpm install` now restores a workspace project's `node_modules` after it was deleted. Before, the install printed "Already up to date" and left the project without the dependencies nested under it. - Under `nodeLinker: hoisted`, `pnpm install` now clears orphaned package directories that an interrupted or failed install leaves in a project's `node_modules`. A directory recorded by the previous install is removed, while an unrecorded directory is moved to `node_modules/.ignored`. A copy already in `.ignored` is never overwritten [#&#8203;13676](https://github.com/pnpm/pnpm/issues/13676). - Packages in an external `virtualStoreDir` can resolve the project's direct dependencies selected by `hoistPattern`. Run `pnpm install --force` to repair an existing installation [#&#8203;5652](https://github.com/pnpm/pnpm/issues/5652). - A repeat install now keeps the fast path when a declared local file dependency is replaced by an override [#&#8203;12892](https://github.com/pnpm/pnpm/issues/12892). ##### Store, build cache, and global virtual store - Files imported from the store now follow the umask of the install that writes them. Installing with a umask of `077` no longer leaves imported files readable by the group and others [#&#8203;3807](https://github.com/pnpm/pnpm/issues/3807). - With the global virtual store, `pnpm rebuild` no longer modifies packages shared with projects that have not approved their build scripts [#&#8203;12302](https://github.com/pnpm/pnpm/issues/12302). - The side-effects cache now restores the symlinks that a build script creates inside a package. A warm install used to replace each of them with a copy of its target [#&#8203;12859](https://github.com/pnpm/pnpm/issues/12859). After upgrading, every package with a build script is built once more. - `pnpm install` now restores cached build artifacts when reinstalling a workspace that uses separate lockfiles [#&#8203;12942](https://github.com/pnpm/pnpm/issues/12942). - The global virtual store and the side-effects cache now key built packages by the Node.js version that the root project's `devEngines.runtime` or `engines.runtime` pins. That is the Node.js their build scripts run with. A dependency that declares its own `engines.runtime` no longer changes the key for every other package. - Concurrent installs that share a global virtual store now run a package's build in its shared slot one at a time. A failed build leaves the slot in place and marks it for the next install to rebuild [#&#8203;15568](https://github.com/pnpm/pnpm/issues/15568). - Concurrent installs no longer fail when they replace the same stale hoisted dependency link. Virtual store cleanup now keeps the temporary lockfiles that concurrent installs are still writing. - `pnpm install` keeps the owner, group, and mode of files already in a shared store, including `index.db`. New store files and directories inherit the store directory's group-write bit. When that directory is setgid, new files inherit its group. pnpm does not change a file's owner or group [#&#8203;12765](https://github.com/pnpm/pnpm/issues/12765). - When `pnpm install` repairs a store file that was modified through a hard link in `node_modules`, the repair now keeps the file's inode on Linux and macOS. Hard-linked copies in other projects are healed at the same time. Before, only the project running the install received the restored content. On Windows the repair still replaces the file, so other projects are healed on their next install [#&#8203;3445](https://github.com/pnpm/pnpm/issues/3445). - A tarball whose integrity pnpm computed during download is now found in the store on the next install. Before, that install downloaded the tarball again once the lockfile recorded the integrity [#&#8203;12562](https://github.com/pnpm/pnpm/issues/12562). - pnpm now warns when it cannot hard link packages from an existing store in the pnpm home directory and uses a store on the project's filesystem. This can happen when the project is on another filesystem, such as a bind-mounted workspace in a container. The warning names both stores and suggests setting `storeDir` [#&#8203;14505](https://github.com/pnpm/pnpm/issues/14505). ##### Resolving and linking dependencies - A peer dependency no longer resolves to two different versions for one package. This happened when the package peer-depends on another package and on one of that package's peers, and it is installed deeper than a direct dependency of the package that provides them [#&#8203;12098](https://github.com/pnpm/pnpm/issues/12098). - An optional peer dependency is no longer resolved from another workspace project's package when the project provides one of that package's own peers at a version it rejects. This avoids bogus unmet peer errors [#&#8203;13989](https://github.com/pnpm/pnpm/issues/13989). - pnpm no longer reports unmet peer dependency warnings for aliased `npm:` peer ranges that a tarball dependency satisfies [#&#8203;11126](https://github.com/pnpm/pnpm/issues/11126). - `pnpm install` now links the executables of auto-installed peer dependencies into the workspace root's `node_modules/.bin`, including after a frozen-lockfile reinstall [#&#8203;8511](https://github.com/pnpm/pnpm/issues/8511). - With `resolutionMode: time-based` and `minimumReleaseAge` both set, `pnpm install` no longer reports a subdependency as too new when only the time-based cutoff excludes it. Such subdependencies used to fail a strict install with `ERR_PNPM_NO_MATURE_MATCHING_VERSION`, or were added to `minimumReleaseAgeExclude` [#&#8203;13569](https://github.com/pnpm/pnpm/issues/13569). A transitive dependency that has no matching version published before the time-based cutoff now resolves to the lowest matching version allowed by `minimumReleaseAge`. pnpm picks a version younger than `minimumReleaseAge` only if no older version matches [#&#8203;16298](https://github.com/pnpm/pnpm/issues/16298). - With `minimumReleaseAge` set, re-resolving the lockfile no longer rewrites the `peerDependencies` recorded for a package whose version did not change. This happened when the registry metadata of a package differed from the `package.json` in its tarball [#&#8203;13988](https://github.com/pnpm/pnpm/issues/13988). - pnpm no longer revalidates cached registry metadata when the registry sends `Cache-Control: max-age=0`, `no-cache`, or `no-store`. It downloads the metadata again, so a version newly published to such a registry is visible on the next install [#&#8203;13487](https://github.com/pnpm/pnpm/issues/13487). - pnpm's built-in package compatibility database no longer applies to a project's own manifest. A project named like a published package, such as `vue-loader`, no longer gains dependencies on `pnpm install` or `pnpm update`. User-configured `packageExtensions` still apply to project manifests [#&#8203;11700](https://github.com/pnpm/pnpm/issues/11700). - Relative local tarball paths in `pnpm.overrides` without an explicit `file:` prefix are now rebased correctly for workspace packages [#&#8203;11131](https://github.com/pnpm/pnpm/issues/11131). - pnpm no longer reports `pnpm-lock.yaml` as broken when a project depends on a package named `constructor`. A `__proto__` key in the lockfile is now kept as a plain entry when pnpm reads or writes the lockfile. It no longer replaces the prototype of the objects pnpm builds from it [#&#8203;11028](https://github.com/pnpm/pnpm/issues/11028). - With `nodeLinker: pnp`, a workspace package can now require another workspace package it depends on [#&#8203;3567](https://github.com/pnpm/pnpm/issues/3567). On Windows, workspace dependency paths in the generated `.pnp.cjs` now use forward slashes. ##### Performance - pnpm now uses less memory when installing a package whose archive is larger than 64 MiB unpacked, and when installing a runtime from a zip archive, such as Node.js on Windows, Deno, or Bun [#&#8203;14164](https://github.com/pnpm/pnpm/issues/14164). - A fresh install reusing a warm global virtual store skips reimporting packages whose target directory is already complete [#&#8203;11112](https://github.com/pnpm/pnpm/issues/11112). - A warm `pnpm install` reuses on-disk package metadata for five minutes when the registry does not send an ETag. Registries that send an ETag, including the public npm registry, still revalidate with a conditional request. `pnpm update` still fetches current metadata [#&#8203;13976](https://github.com/pnpm/pnpm/issues/13976). ##### Patched dependencies - `pnpm install` now repairs a `pnpm-lock.yaml` whose `(patch_hash=<hash>)` dependency paths disagree with its `patchedDependencies` map, including paths that lack the hash their patch calls for. pnpm previously accepted such a lockfile as up to date and kept the old patched files. `pnpm install --frozen-lockfile` now fails on such a lockfile with `ERR_PNPM_INCONSISTENT_PATCH_HASH`. It fails with `ERR_PNPM_UNCHECKABLE_PATCH_HASH` when a patch hash in the lockfile is malformed, or when the lockfile lacks the package version or patch entry that the check needs [#&#8203;15336](https://github.com/pnpm/pnpm/pull/15336). - `pnpm install` now fails with `ERR_PNPM_PATCH_NOT_FOUND` when a patch file listed in `patchedDependencies` does not exist. It used to fail with a raw `ENOENT` error and a stack trace [#&#8203;5268](https://github.com/pnpm/pnpm/issues/5268). - pnpm now fails with `ERR_PNPM_INVALID_PATCHED_DEPENDENCY` when `patchedDependencies` has an invalid shape or contains a non-string value. - `engineStrict` now checks the patched `package.json` when a `patchedDependencies` entry changes `engines`. A patch that relaxes `engines.node` no longer fails the install against the published range [#&#8203;9603](https://github.com/pnpm/pnpm/issues/9603). - `pnpm patch` now applies the existing patch file to the edit directory of a git-hosted dependency, as it already does for packages from the registry [#&#8203;9699](https://github.com/pnpm/pnpm/issues/9699). - `pnpm patch-commit` now fails with an error when `git` cannot be found in `PATH`. It previously reported that no changes were found [#&#8203;8666](https://github.com/pnpm/pnpm/issues/8666). ##### Workspaces and filtering - `pnpm install` refreshes injected copies of workspace packages when source projects are rebuilt. Injected copies previously stayed stale until `pnpm install --force` [#&#8203;4407](https://github.com/pnpm/pnpm/issues/4407). - Scripts listed in `syncInjectedDepsAfterScripts` now update injected dependencies while they run. A watcher on the injected package, such as a dev server, sees each change before the script exits [#&#8203;4410](https://github.com/pnpm/pnpm/issues/4410). - `pnpm install` no longer fails for an injected workspace dependency whose package publishes from a `publishConfig.directory` that its own `prepare` script builds. The injected copy now picks up that directory once `prepare` finishes building it. `pnpm install --frozen-lockfile` no longer reports the dependency as outdated while the directory has not been built yet [#&#8203;7811](https://github.com/pnpm/pnpm/issues/7811). - With `sharedWorkspaceLockfile: false`, an injected workspace package that has lifecycle scripts is now hard linked into the projects that depend on it. Before, pnpm left a plain copy, so later edits to the package did not reach those projects [#&#8203;9828](https://github.com/pnpm/pnpm/issues/9828). - `injectWorkspacePackages` now hard links a workspace dependency declared with a relative path, such as `workspace:../foo`, the same way it already does for `workspace:*` [#&#8203;10446](https://github.com/pnpm/pnpm/issues/10446). - `pnpm install` no longer creates a `node_modules` symlink inside the `publishConfig.directory` of a workspace package linked with `linkDirectory`. A build tool that cleaned its output directory through that symlink deleted the files of the package's dependencies. `pnpm install` also removes a symlink that an earlier install left there [#&#8203;16226](https://github.com/pnpm/pnpm/issues/16226). - When `verifyDepsBeforeRun` triggers an install before a filtered `pnpm run` or `pnpm exec`, pnpm now installs only the selected projects and their dependencies. A later filtered command also installs a selected project that an earlier filtered install skipped [#&#8203;11865](https://github.com/pnpm/pnpm/issues/11865). - `pnpm import` in a workspace now keeps the versions pinned by a `yarn.lock` inside a workspace project [#&#8203;4385](https://github.com/pnpm/pnpm/issues/4385). - Installing with `pnprServer` set now records the pnpmfile checksum in the lockfile, so a later `pnpm install --frozen-lockfile` accepts that lockfile. A frozen install through the pnpr server now fails if the pnpmfile changed. If the pnpmfile defines a `readPackage`, `afterAllResolved` or `preResolution` hook or custom resolvers, pnpm resolves dependencies locally and prints a warning that the pnpr server was not used [#&#8203;14460](https://github.com/pnpm/pnpm/issues/14460). Installing through a pnpr server now links a workspace project at the directory its `publishConfig.directory` names. An install that resolves through a server which does not forward the setting fails with `ERR_PNPM_PNPR_PUBLISH_DIRECTORY_MISMATCH`. The server rejects a `publishConfig.directory` that points outside its project. ##### Adding, updating, and removing dependencies - With `autoInstallPeers`, `pnpm add` and `pnpm remove` in a workspace project keep the locked version of a peer dependency the project declares. In a workspace where another project depended on a different version of that package, the peer could switch to that version [#&#8203;11225](https://github.com/pnpm/pnpm/issues/11225). - Adding a dependency now keeps unrelated transitive dependencies on their locked versions [#&#8203;11456](https://github.com/pnpm/pnpm/issues/11456). - `pnpm update --recursive <pkg>` no longer changes the version of a peer dependency that another workspace project installs automatically. Such a peer could move to a version outside the range the project declares, for example to React 19 in a project that declares `react: ^18.3.1` [#&#8203;14928](https://github.com/pnpm/pnpm/issues/14928). - `pnpm update package@beta` on a dependency declared as `catalog:` now updates the catalog entry and keeps `catalog:` in `package.json`. Before, pnpm wrote the resolved specifier to `package.json` [#&#8203;13399](https://github.com/pnpm/pnpm/issues/13399). - `pnpm update` now applies an override that references a catalog with the catalog's new value when the update bumps that catalog entry. Before, the packages the override targets kept the old version in the lockfile [#&#8203;12159](https://github.com/pnpm/pnpm/issues/12159). - `pnpm add <dir>` now warns when the added directory declares peer dependencies, as `pnpm link` does. The directory is saved as a `link:` dependency, and its peers are not resolved from the project that adds it. Use the `file:` protocol to have them resolved [#&#8203;5523](https://github.com/pnpm/pnpm/issues/5523). ##### Running scripts and commands - `pnpm run` and `pnpm exec` no longer install dependencies automatically when the root `package.json` still keeps `overrides`, `packageExtensions`, `patchedDependencies`, or `ignoredOptionalDependencies` in its `pnpm` field. pnpm no longer reads that field, so the install rewrote the lockfile without those settings. The command now fails and asks to move the settings to `pnpm-workspace.yaml` [#&#8203;16278](https://github.com/pnpm/pnpm/issues/16278). - `pnpm run` no longer reinstalls dependencies when a `node_modules` directory installed outside CI is used with `CI=true`, or the other way around [#&#8203;12337](https://github.com/pnpm/pnpm/issues/12337). - pnpm no longer hangs after a lifecycle script exits while a process it started in the background keeps the script's output open. pnpm stops reading that output one second after the script exits [#&#8203;5730](https://github.com/pnpm/pnpm/issues/5730). - A signal sent to pnpm, such as `SIGTERM`, now reaches the pnpm that pnpm switches to because of `packageManager` or `devEngines.packageManager`, and the one that `pnpm with` runs. The signal used to be dropped, so scripts running under that pnpm never got to shut down [#&#8203;9948](https://github.com/pnpm/pnpm/issues/9948). - `pnpm run` exits with the code of a script that handles Ctrl+C and shuts down. A script that finished cleanly is not reported as a lifecycle failure. The commands after it in the same script still run [#&#8203;9945](https://github.com/pnpm/pnpm/issues/9945). - `pnpm run` and lifecycle scripts use the configured `scriptShell`, including Git Bash on Windows, when `shellEmulator` is also enabled. `shellEmulator` still runs scripts when `scriptShell` is not set. Extra arguments passed to `pnpm run` are quoted for the shell that runs the script, so a Windows path stays intact [#&#8203;14719](https://github.com/pnpm/pnpm/issues/14719). - `pnpm -r run /regexp/` now honors the `tasks` `dependsOn` declared for each script the selector matches, like running the script by name does. Matched scripts that depend on each other run in order. Each matched script runs once [#&#8203;15596](https://github.com/pnpm/pnpm/issues/15596). - Commands run from a POSIX shell through a dependency's own `node_modules/.bin`, such as `node_modules/vite/node_modules/.bin/esbuild`, no longer fail with `MODULE_NOT_FOUND` [#&#8203;10189](https://github.com/pnpm/pnpm/issues/10189). - `pnpm rebuild` with `nodeLinker: hoisted` no longer puts one package's parent `node_modules/.bin` directories on the `PATH` of the packages it builds after it. ##### Publishing, packing, and deploying - `pnpm publish` now waits at least 5 minutes for the registry to answer a publish request, like npm. This fixes "409 Conflict - Failed to save packument" errors when the registry is slow to answer [#&#8203;11454](https://github.com/pnpm/pnpm/issues/11454). - `pnpm deploy` with a shared lockfile now copies workspace dependencies into the deploy directory, even when `packageImportMethod` is set to `hardlink`. Previously, their files were hard-linked to the workspace sources, so editing a source file also changed the deployed copy [#&#8203;12176](https://github.com/pnpm/pnpm/issues/12176). - `pnpm deploy --prod` no longer fails with `ERR_PNPM_OUTDATED_LOCKFILE` when the deployed project declares a `devEngines.runtime` with `onFail: download`. The runtime stays out of the deployed `node_modules` with the rest of the dev dependencies [#&#8203;15703](https://github.com/pnpm/pnpm/issues/15703). - `pnpm deploy --legacy` no longer leaves broken links to nested local dependencies of workspace packages [#&#8203;9575](https://github.com/pnpm/pnpm/issues/9575). - `pnpm deploy` no longer creates extra directories inside the deploy target and workspace projects when using a relative deploy path [#&#8203;10981](https://github.com/pnpm/pnpm/issues/10981). ##### Manifests and configuration files - Settings given on the command line, such as `--registry` and `--store-dir`, now take precedence over the values a pnpmfile `updateConfig` hook sets [#&#8203;14063](https://github.com/pnpm/pnpm/issues/14063). - An `updateConfig` hook that returns `registriesByScope` without the `default` or `@jsr` entry no longer crashes the install with `Invalid URL`. A missing `default` keeps the configured `registry`, and a missing `@jsr` falls back to the built-in JSR registry [#&#8203;15619](https://github.com/pnpm/pnpm/issues/15619). The hook's `registry` and the `default` entry of its `registriesByScope` now set one default registry, which installs, `pnpm publish`, and `pnpm login` all use. If a hook changes both, `registry` wins. A route that is not a string fails with `ERR_PNPM_INVALID_UPDATE_CONFIG_RESULT`. - An `updateConfig` hook in `.pnpmfile.cjs` has to use `config.registriesByScope`, `config.registriesByPrefix`, and `config.registryOptionsByUrl`. These registry lookups were renamed in pnpm 11.23.0 from `config.registries`, `config.namedRegistries`, and `config.registryOptions` [#&#8203;15620](https://github.com/pnpm/pnpm/issues/15620). - An async `updateConfig` hook that resolves to `undefined` now fails with `ERR_PNPM_CONFIG_IS_UNDEFINED`, as a synchronous hook that returns `undefined` already did. - `pnpm config set --location=project` and `pnpm config delete --location=project`, run from a package inside a workspace, now write settings that belong in `pnpm-workspace.yaml` to the workspace root's `pnpm-workspace.yaml`. Before, they created a new `pnpm-workspace.yaml` in the current package, which made that package the workspace root. Settings stored in `.npmrc` are still written to the current directory [#&#8203;13757](https://github.com/pnpm/pnpm/issues/13757). - pnpm now reads the workspace directory override from `PNPM_CONFIG_WORKSPACE_DIR`, like other settings. `NPM_CONFIG_WORKSPACE_DIR` still works as a fallback [#&#8203;16275](https://github.com/pnpm/pnpm/issues/16275). - A `${VAR}` placeholder in `.npmrc` or `pnpm-workspace.yaml` whose name matches a built-in object property, such as `${toString}`, is now treated as an unset variable. It used to be replaced with the source text of a JavaScript function. - pnpm now rejects a falsy non-array `packages` field in `pnpm-workspace.yaml`, such as `packages: false`, with an error. It used to treat the field as omitted. ##### Global packages, pnpm versions, and runtimes - `pnpm update --global` now reinstalls the global packages that pnpm 10 installed into the previous global directory, `<global-dir>/5`, so their commands are linked into the pnpm home `bin` directory again and `pnpm list --global` lists them. Once every package is migrated, pnpm deletes the previous directory and the commands pnpm 10 linked into the pnpm home [#&#8203;11528](https://github.com/pnpm/pnpm/issues/11528). - `pnpm env remove --global` deletes Node.js versions that pnpm installed into its own store, including when another tool installed pnpm [#&#8203;8357](https://github.com/pnpm/pnpm/issues/8357). - `pnpm self-update` no longer suggests a downgrade when `minimumReleaseAge` holds back the registry's `latest` release. It now says that release is still within the cutoff [#&#8203;12006](https://github.com/pnpm/pnpm/issues/12006). - `@pnpm/exe` no longer ships a binary for arm64 musl Linux, such as Alpine on ARM. The published binary crashed with a segmentation fault at startup. Installing `@pnpm/exe` on that platform now fails with an error that suggests `npm install -g pnpm` or pnpm 12 [#&#8203;10443](https://github.com/pnpm/pnpm/issues/10443). - The macOS and Linux release archives no longer include Windows-only files, such as `node-gyp.cmd` and the `fastlist` executables [#&#8203;11352](https://github.com/pnpm/pnpm/issues/11352). ##### Windows and WSL - On Windows, `pnpm run` now passes the arguments after the script name to the script as typed. Before, `cmd` expanded `%VAR%` in them and backslashes arrived doubled. Line breaks still arrive as the two characters `\n`, because `cmd` cannot pass them. The command line pnpm prints for the script quotes the arguments the same way on every platform [#&#8203;16257](https://github.com/pnpm/pnpm/issues/16257). - On Windows, command shims now run tools whose paths contain non-ASCII characters [#&#8203;6999](https://github.com/pnpm/pnpm/issues/6999). The PowerShell shims do so in Windows PowerShell 5.1 too [#&#8203;16217](https://github.com/pnpm/pnpm/issues/16217). - On Windows, the `.cmd` command shims in `node_modules/.bin` now keep a `%` in the project path. Before, cmd.exe expanded it as a variable reference, so the command received a mangled `NODE_PATH` [#&#8203;15716](https://github.com/pnpm/pnpm/issues/15716). - Bin shims in `node_modules/.bin` run from Cygwin on Windows again. The shims passed a `/cygdrive/c/...` path to the Windows `node` found on `PATH`, so Node.js failed with `Cannot find module 'C:\cygdrive\c\...'` [#&#8203;12845](https://github.com/pnpm/pnpm/issues/12845). - `pnpm setup` no longer writes the `pn.ps1`, `pnpx.ps1`, and `pnx.ps1` PowerShell wrappers. It also removes the ones an earlier setup wrote. PowerShell now runs `pn`, `pnpx`, and `pnx` through their `.cmd` wrappers, like `pnpm` itself. Before, these aliases failed with a "not digitally signed" error wherever the execution policy blocks unsigned scripts [#&#8203;8444](https://github.com/pnpm/pnpm/issues/8444). - On Windows, globally installed `@pnpm/exe` commands now run in the invoking PowerShell console and return their exit status [#&#8203;6503](https://github.com/pnpm/pnpm/issues/6503). - On Windows, installing `@pnpm/exe` with npm inside a project now writes `node_modules/.bin` shims that run the standalone executable [#&#8203;15688](https://github.com/pnpm/pnpm/issues/15688). - On Windows, `pnpm env use -g` and `pnpm add -g node@runtime:<version>` now replace a `node.exe` in the global bin directory that is a broken symlink. Previously they failed with `ENOENT` [#&#8203;5411](https://github.com/pnpm/pnpm/issues/5411). - On Windows, pnpm expands nested `%VAR%` references in `PNPM_HOME` and the other directory environment variables it uses for its home, store, cache, state, and config directories. pnpm fails with an error when a `%VAR%` reference remains after expansion [#&#8203;13236](https://github.com/pnpm/pnpm/issues/13236). - On Windows, if the global bin directory is not in `PATH` and a `PATH` entry still contains an unexpanded variable such as `%PNPM_HOME%`, the error now names that entry. A variable referenced from the user `Path` must be set to a full path and stored as a plain string (`REG_SZ`) for the entry to expand [#&#8203;5283](https://github.com/pnpm/pnpm/issues/5283). - On Windows, `pnpm setup` no longer garbles non-ASCII characters in existing `Path` entries [#&#8203;6346](https://github.com/pnpm/pnpm/issues/6346). - On Windows, `pnpm setup` repairs the `PNPM_HOME` registry type left by older pnpm versions, even when the configured directory has not changed. - On Windows, the `ERR_PNPM_BAD_ENV_FOUND` error of `pnpm setup` now shows the value `PNPM_HOME` is currently set to. It used to show the directory pnpm wanted to set. - On Windows, `pnpm install` no longer skips a dependency's build script on a later install when the script changes nothing inside the package directory [#&#8203;15667](https://github.com/pnpm/pnpm/issues/15667). - On Windows, pnpm now retries writing the workspace state file while another process, such as an antivirus scanner, briefly holds it open [#&#8203;14550](https://github.com/pnpm/pnpm/issues/14550). ##### Inspecting dependencies - `pnpm licenses list` now reports the actual on-disk package locations when using `nodeLinker: hoisted` or `shamefully-hoist: true` [#&#8203;8589](https://github.com/pnpm/pnpm/issues/8589). `pnpm licenses list --json` now includes every installed copy of a package in its `paths` array, including hoisted copies and isolated installations with different peer dependencies. Its paths also exist on disk when the isolated linker uses a custom `modulesDir`. - `pnpm list` now shows the correct path of a `link:` dependency that points to a directory on another drive on Windows. The path used to be appended to the project directory, such as `C:\project\D:\lib`, and `pnpm list --long` could not show the package's details [#&#8203;10362](https://github.com/pnpm/pnpm/issues/10362). - `pnpm root` now prints the configured `modulesDir`. It used to print `node_modules` regardless of the setting. A project's own `modulesDir` from `packageConfigs` is printed too [#&#8203;9113](https://github.com/pnpm/pnpm/issues/9113). - `pnpm audit` and `pnpm audit signatures` now fail with an error when the lockfile contains unresolvable dependency references [#&#8203;13638](https://github.com/pnpm/pnpm/issues/13638). ##### Output and messages - With the default and append-only reporters, installs with `--loglevel warn` or `--loglevel error` now print the full output of a failed install script. The output of successful scripts, including the root project's own install hooks, stays hidden. With `--loglevel warn`, pnpm also prints ignored build script warnings. - The lockfile verification error now suggests relaxing the policy that flagged an entry only if a fresh resolution still fails and you trust the affected packages. Errors from checks that no policy controls, such as a missing tarball integrity, no longer suggest relaxing a policy [#&#8203;14411](https://github.com/pnpm/pnpm/issues/14411). - `pnpm run --recursive` now prints GitLab CI collapsible sections that GitLab recognizes. The section markers used to appear as raw text in the job log. - Local tarball dependencies using the file protocol are no longer counted as downloaded in the progress banner [#&#8203;1103](https://github.com/pnpm/pnpm/issues/1103). <!-- 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 --> ### [`v11.28.0`](https://github.com/pnpm/pnpm/releases/tag/v11.28.0): pnpm 11.28 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.27.1...v11.28.0) pnpm 11.28.0 adds the `forceIgnoresPlatform` setting and `pnpm update --peer`, and fixes many bugs in `pnpm deploy`, `--filter`, `nodeLinker: hoisted`, and custom `modulesDir` setups. This release also carries security fixes for shell completion, bin shims on Nix, lifecycle scripts inside a custom `modulesDir`, and `userAgent` placeholders in `pnpm-workspace.yaml`. ##### Minor Changes - Added the `forceIgnoresPlatform` setting. When it is `false`, `pnpm install --force` skips optional dependencies whose `os`, `cpu` or `libc` do not match the host instead of installing all of them. The default stays `true` [#&#8203;6133](https://github.com/pnpm/pnpm/issues/6133). ##### Patch Changes ##### Security - pnpm no longer expands environment variables in a `userAgent` set in a project's `pnpm-workspace.yaml`. A `userAgent` with a placeholder in that file is now ignored. Before this fix, pnpm sent the variable's value to the configured registry [#&#8203;15415](https://github.com/pnpm/pnpm/issues/15415). - pnpm no longer treats packages inside a custom `modulesDir` as workspace projects, including one that `packageConfigs` sets for a project. Before, with a `modulesDir` such as `vendor` and a `packages` pattern such as `**`, a repeat install ran the lifecycle scripts of dependencies that `allowBuilds` had not approved [#&#8203;15412](https://github.com/pnpm/pnpm/pull/15412). - On Nix, a dependency's bin named like a system utility such as `sed` can no longer redirect a POSIX bin shim or the `pnpm`, `pn`, `pnpx`, and `pnx` launchers. The shims and launchers now ignore `node_modules` and relative `PATH` entries while they locate their own files. Installing again replaces the shims already in `node_modules` [#&#8203;14883](https://github.com/pnpm/pnpm/issues/14883). - Shell completion now omits candidates containing control or invisible formatting characters, and fish completion omits names containing backslashes. Package and script names can no longer inject extra completion records or terminal escape sequences. - Commands that run pnpm again, such as `pnpm runtime set` and `pnpm env use`, no longer re-run a script that only looks like pnpm. A script named `pnpm` or `pn` that another package installed was run as though it were pnpm. - `pnpm store prune` now leaves a `dlx` cache root that is a symlink or Windows junction untouched. Cleanup no longer removes directories through that link. ##### Installing packages - `pnpm install` now fails at once when a registry or tarball server presents a TLS certificate that fails verification, such as a self-signed or expired one. The error names the certificate problem. Such requests were retried for more than a minute [#&#8203;9134](https://github.com/pnpm/pnpm/issues/9134). - `pnpm install` no longer appears to hang when a git dependency is fetched over SSH and ssh asks for a key passphrase or a host key confirmation. pnpm now runs ssh in batch mode, so the install fails right away with the ssh error, and a key that needs a passphrase has to be loaded into an SSH agent first. An ssh command selected through `GIT_SSH_COMMAND`, `GIT_SSH`, or the `core.sshCommand` git setting is kept as is [#&#8203;2227](https://github.com/pnpm/pnpm/issues/2227). - pnpm no longer crashes on startup when the temporary directory set by `TMPDIR`, `TEMP`, or `TMP` does not exist [#&#8203;4960](https://github.com/pnpm/pnpm/issues/4960). - `pnpm install --silent` no longer fails when the install is delegated to pacquet. pnpm also stops passing `-s`, `--loglevel` and the other reporting flags to pacquet [#&#8203;11936](https://github.com/pnpm/pnpm/issues/11936). - Fixed `pnpm install` failing with `EEXIST` when a concurrent install cleared the file or directory that was occupying a symlink path. On Windows, a symlink another process is still holding is no longer moved aside and recreated. - `pnpm install` no longer fails when writing the workspace state file encounters an error. Failures to update the state file now emit a warning instead of aborting the install [#&#8203;14550](https://github.com/pnpm/pnpm/issues/14550). - Installing or adding dependencies no longer fails when a previously installed local tarball file was deleted from disk [#&#8203;8367](https://github.com/pnpm/pnpm/issues/8367). - `pnpm install` now reads the same local tarball it installs when a dependency's absolute `file:` path contains `..`. Such a path could install a different tarball than the one it read, failing with `ERR_PNPM_TARBALL_INTEGRITY`, or fail to resolve at all. - `pnpm install --frozen-lockfile` now rejects changed local tarballs, even when the previous archive contents are in the store [#&#8203;1889](https://github.com/pnpm/pnpm/issues/1889). - `pnpm add` and `pnpm install` now support installing bzip2 compressed tarballs [#&#8203;6761](https://github.com/pnpm/pnpm/issues/6761). - `pnpm install` now fetches committed submodules of git dependencies [#&#8203;1470](https://github.com/pnpm/pnpm/issues/1470). - Interrupting `pnpm install` with Ctrl+C or SIGTERM no longer leaves a temporary lockfile (`.pnpm-lock.yaml.*.tmp`) behind in the project [#&#8203;1418](https://github.com/pnpm/pnpm/issues/1418). - `pnpm install` and `pnpm run` now reinstall a single project that was moved or renamed together with its `node_modules`. Before, they reported "Already up to date" while links such as Windows junctions still pointed at the old location [#&#8203;9512](https://github.com/pnpm/pnpm/issues/9512). - `pnpm install` now relinks a direct dependency whose link in `node_modules` points to a missing target. Before, it reported "Already up to date" and left the broken link [#&#8203;9758](https://github.com/pnpm/pnpm/issues/9758). - `pnpm install` and `pnpm add` no longer skip optional dependencies that the Node.js version resolved for a `devEngines.runtime` range supports, when the range uses `onFail: download`. An explicitly set `nodeVersion` still takes priority [#&#8203;14628](https://github.com/pnpm/pnpm/issues/14628). - `pnpm install` now uses the running Node.js when `devEngines.runtime` declares a range without `onFail: download`. Optional dependencies supported by the active Node.js are no longer skipped [#&#8203;15230](https://github.com/pnpm/pnpm/issues/15230). - `pnpm install --engine-strict` now respects `engines` relaxed by `readPackage` hooks in `.pnpmfile.cjs` [#&#8203;15482](https://github.com/pnpm/pnpm/issues/15482). - `pnpm install` now applies changes to or removal of a global `readPackage` hook when an existing lockfile is present [#&#8203;15136](https://github.com/pnpm/pnpm/issues/15136). - The project's `.pnpmfile.mjs` or `.pnpmfile.cjs` now runs after the pnpmfiles of config dependency plugins [#&#8203;9891](https://github.com/pnpm/pnpm/issues/9891). - A `readPackage` hook that sets a dependency range to a value other than a string, such as `undefined`, now fails the install with an error that names the dependency, the package, and the pnpmfile. Delete the property to remove a dependency [#&#8203;5517](https://github.com/pnpm/pnpm/issues/5517). - `pnpm install --prod` and other installs that skip `devDependencies` no longer run the `pnpm:devPreinstall` script [#&#8203;7065](https://github.com/pnpm/pnpm/issues/7065). They skip `prepare` lifecycle scripts too, as does `pnpm install` given package arguments. `pnpm deploy` does not run the `prepare` scripts of the deployed project [#&#8203;7282](https://github.com/pnpm/pnpm/issues/7282). - The root project's `preinstall` script now runs before dependencies are resolved and linked. A guard such as `npx only-allow yarn` can stop the install before pnpm populates `node_modules` [#&#8203;3760](https://github.com/pnpm/pnpm/issues/3760). - `pnpm install --prod`, `pnpm fetch --prod` and `pnpm deploy --prod` no longer install a devDependency that is only there to satisfy an optional peer dependency of a production dependency. `pnpm list`, `pnpm why`, `pnpm licenses`, `pnpm sbom` and `pnpm audit` leave it out of `--prod` results too. The same applies to `--dev`. A peer that is not optional is still installed and audited [#&#8203;15344](https://github.com/pnpm/pnpm/issues/15344). - `pnpm prune --prod` and production installs now prune excluded development dependencies even when lockfile generation is disabled. - `pnpm fetch` now also installs the pnpm version that `pnpm-lock.yaml` pins, when it differs from the running pnpm. A later `pnpm install --offline` that switches to the pinned version no longer fails because that version is missing from the store [#&#8203;11808](https://github.com/pnpm/pnpm/issues/11808). - A dependency that ships a `binding.gyp` and sets `gypfile: false` no longer gets the `node-gyp rebuild` install script pnpm synthesizes for it. Such a dependency needs no `allowBuilds` entry and is no longer listed under "Ignored build scripts". - `pnpm install` no longer adds `allowBuilds` placeholder entries to `pnpm-workspace.yaml` when it runs in CI or without a terminal. Interactive installs still add them [#&#8203;11574](https://github.com/pnpm/pnpm/issues/11574). - Installing through a pnpr server now installs a project's peer dependencies when `autoInstallPeers` is enabled. A project that declared only peer dependencies failed with `ERR_PNPM_OUTDATED_LOCKFILE` or skipped its peers [#&#8203;14833](https://github.com/pnpm/pnpm/issues/14833). ##### Resolving and linking dependencies - pnpm now installs a dependency that a package also declares as an optional peer dependency, for example `lightningcss` in some vite builds. The dependency was missing from `node_modules`, so the package failed to import it [#&#8203;8912](https://github.com/pnpm/pnpm/issues/8912). - Removal overrides such as `"parent>peer": "-"` now prevent optional peers from being installed from another workspace package [#&#8203;15008](https://github.com/pnpm/pnpm/issues/15008). - Removing an entry from `overrides` now re-resolves the packages it targeted. A version the override had locked is no longer kept just because the declared range still accepts it [#&#8203;4587](https://github.com/pnpm/pnpm/issues/4587). - `packageExtensions` and `overrides` entries with a ranged selector (such as `@<X` or `@*`) no longer match a dependency that has no `package.json`, such as a local directory dependency [#&#8203;15007](https://github.com/pnpm/pnpm/issues/15007). - Trim leading and trailing whitespace from dependency override selectors in `pnpm.overrides` [#&#8203;6356](https://github.com/pnpm/pnpm/issues/6356). - With `trustPolicy: no-downgrade`, pnpm now resolves the newest matching version that is not a trust downgrade. Previously a dependency failed with `ERR_PNPM_TRUST_DOWNGRADE` even when an older version satisfied its range. `pnpm self-update` picks its target version the same way. A request for an exact version still fails [#&#8203;14176](https://github.com/pnpm/pnpm/issues/14176). - `pnpm install` and `pnpm update` now resolve a dependency range to the newest matching version that is not deprecated. A version already recorded in the lockfile is still used [#&#8203;15128](https://github.com/pnpm/pnpm/issues/15128). - `pnpm add` and `pnpm remove` no longer move unrelated transitive dependencies to other versions. Adding a package and then removing it now leaves `pnpm-lock.yaml` unchanged. Before, the dependencies of auto-installed peers and `npm:` aliased subdependencies could move to a newer version that was already in the lockfile [#&#8203;11859](https://github.com/pnpm/pnpm/issues/11859). - `pnpm dedupe` now moves transitive dependencies to the version a `catalog:` dependency pins, as it already did for versions written directly in `package.json`. - `pnpm install --ignore-pnpmfile` no longer removes `pnpmfileChecksum` from an up-to-date `pnpm-lock.yaml`. `pnpm install --frozen-lockfile --ignore-pnpmfile` no longer fails with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` when the lockfile records a `pnpmfileChecksum`. A command that resolves dependencies with the pnpmfile ignored still writes the lockfile without it [#&#8203;10944](https://github.com/pnpm/pnpm/issues/10944). - `pnpm install --frozen-lockfile` now succeeds when an optional dependency was unresolvable and skipped by the install that wrote the lockfile. Previously, frozen installs failed with `ERR_PNPM_OUTDATED_LOCKFILE`. The notice states that the dependency could not be resolved and names the requested range [#&#8203;3960](https://github.com/pnpm/pnpm/issues/3960). - pnpm no longer rewrites `packageManagerDependencies` in `pnpm-lock.yaml` when that block pins `@pnpm/exe` beside `pnpm`. The rewrite ran on every command, so `pnpm list` left a clean working tree dirty, and `pnpm version` then refused to run [#&#8203;14926](https://github.com/pnpm/pnpm/issues/14926). - `pnpm import` and fresh resolutions now record `integrity` for git-hosted tarballs, such as `codeload.github.com` URLs, even when the tarball is already in the store [#&#8203;13338](https://github.com/pnpm/pnpm/issues/13338). - Merging lockfiles now preserves recorded configuration fields such as `overrides`, `neverBuiltDependencies`, `patchedDependencies`, `packageExtensionsChecksum`, `settings`, and `catalogs` [#&#8203;8366](https://github.com/pnpm/pnpm/issues/8366). - A lockfile entry whose resolution is unchanged now keeps its recorded `deprecated` message [#&#8203;5772](https://github.com/pnpm/pnpm/issues/5772). - pnpm no longer writes a package's legacy array-form `engines`, such as `["node >= 0.8"]`, to the lockfile. It was recorded as an object keyed by index, such as `{'0': node >= 0.8}` [#&#8203;4518](https://github.com/pnpm/pnpm/issues/4518). - With `nodeLinker: hoisted`, `hoistWorkspacePackages` now links each workspace project that `hoistPattern` or `publicHoistPattern` selects into the root `node_modules`, unless a hoisted package or a root dependency already uses its name. The project's bins are linked into the root `node_modules/.bin` [#&#8203;7553](https://github.com/pnpm/pnpm/issues/7553). - Workspace projects that `hoistPattern` or `publicHoistPattern` selects are now hoisted on every install. A project added to the workspace was not hoisted until `node_modules` was deleted and reinstalled. A workspace that installs nothing from a registry hoisted none of its projects at all [#&#8203;3642](https://github.com/pnpm/pnpm/issues/3642). - With `nodeLinker: hoisted`, `pnpm install` now removes the commands of the packages it removes from `node_modules/.bin`, such as a nested copy deduped into the root `node_modules` [#&#8203;7568](https://github.com/pnpm/pnpm/issues/7568). - `pnpm install` now links a dependency's bin even when the bin's file does not exist yet, such as a workspace package's bin that a build script creates after install. Previously pnpm printed a `Failed to create bin` warning. The command then stayed missing until `node_modules` was removed [#&#8203;10007](https://github.com/pnpm/pnpm/issues/10007), [#&#8203;10216](https://github.com/pnpm/pnpm/issues/10216). - Executable linking now makes a bin executable for every user. A target with only some execute permission bits set was left non-executable for other users [#&#8203;3699](https://github.com/pnpm/pnpm/issues/3699). Bin linking leaves workspace and linked dependency files outside `node_modules` unchanged. - Dependencies and executable binaries are now correctly linked and accessible for workspace packages using `publishConfig.directory` and `publishConfig.linkDirectory` [#&#8203;8338](https://github.com/pnpm/pnpm/issues/8338). ##### Workspaces and filtering - Fixed `pnpm install` for workspace projects reached through a symlink, such as a `packages` directory that links to a folder outside the workspace. pnpm now installs their dependencies, and the links in their `node_modules` resolve [#&#8203;1044](https://github.com/pnpm/pnpm/issues/1044). - A dependency declared with `catalog:` now counts as a workspace dependency when its catalog entry points at a workspace project, for example `workspace:*` [#&#8203;15587](https://github.com/pnpm/pnpm/issues/15587). With `linkWorkspacePackages` enabled, so does an `npm:` alias of a workspace project, such as `"math-alias": "npm:math@^1.0.0"`. `pnpm -r run` runs that project first. `--filter <pkg>...` selects it. - A `workspace:` dependency now resolves to a workspace project whose version is not valid semver, such as `1` or `1.0`. `workspace:*`, `workspace:^`, and `workspace:~` match it. A range identical to the version also matches it [#&#8203;4567](https://github.com/pnpm/pnpm/issues/4567). - A `workspace:` dependency with an exact version now resolves to a workspace project whose version carries SemVer build metadata. For example, `workspace:0.5.6-next.3` matches a project at `0.5.6-next.3+f60facc` [#&#8203;6483](https://github.com/pnpm/pnpm/issues/6483). A workspace project with build metadata is no longer skipped when it matches the requested range and has the same version precedence as the registry package [#&#8203;2812](https://github.com/pnpm/pnpm/issues/2812). - Secondary dependencies now prefer the version resolved by the local project's direct dependencies over versions from sibling workspace projects [#&#8203;7191](https://github.com/pnpm/pnpm/issues/7191). - `pnpm install` now re-resolves a workspace project's auto-installed peer dependency when another workspace project changes its specifier for that package to one that excludes the locked version but still overlaps the peer range. The peer then resolves to the version a fresh install would pick [#&#8203;11800](https://github.com/pnpm/pnpm/issues/11800). - `pnpm install --frozen-lockfile` now fails with `ERR_PNPM_OUTDATED_LOCKFILE` when `pnpm-lock.yaml` lists a workspace project whose directory or manifest file is missing. The install used to report success without installing that project's dependencies [#&#8203;7667](https://github.com/pnpm/pnpm/issues/7667). - `pnpm install --frozen-lockfile` now fails when a workspace package's version no longer satisfies the range that a dependent workspace project declares for it. This includes injected workspace dependencies [#&#8203;7823](https://github.com/pnpm/pnpm/issues/7823). - `pnpm install -r` now installs every workspace project when `recursiveInstall` is set to `false` in `pnpm-workspace.yaml` [#&#8203;7504](https://github.com/pnpm/pnpm/issues/7504). - `pnpm install` with `--filter` now installs only the dependencies of the selected projects when using `nodeLinker: hoisted` [#&#8203;8882](https://github.com/pnpm/pnpm/issues/8882). - `pnpm install` now updates an injected workspace dependency after that package's own dependencies change, when `shared-workspace-lockfile` is `false` [#&#8203;7209](https://github.com/pnpm/pnpm/issues/7209). - `syncInjectedDepsAfterScripts` now copies files into injected dependencies when `node_modules` is on another filesystem than the package sources. The sync previously failed with a cross-device link error and made the script run exit with an error [#&#8203;14703](https://github.com/pnpm/pnpm/issues/14703). - Fixed injected workspace dependency synchronization failing with `EPERM` on Windows when removing nested directories. - Workspace discovery now returns one project per directory when multiple manifest formats are present. It selects `package.json`, then `package.json5`, then `package.yaml` [#&#8203;3027](https://github.com/pnpm/pnpm/issues/3027). - Wildcards in negated `packages` patterns of `pnpm-workspace.yaml` now match directories whose names start with a dot. For example, `!packages/**` now also excludes `packages/.dev/tool` when another pattern includes `.dev` explicitly. - pnpm now warns when a workspace install covers a project that has its own `pnpm-workspace.yaml`. The nested file's settings, such as `patchedDependencies`, do not apply when the outer workspace installs that project. pnpm reads settings only from the `pnpm-workspace.yaml` at the workspace root [#&#8203;11724](https://github.com/pnpm/pnpm/issues/11724). - pnpm now warns when `shared-workspace-lockfile` is passed on the command line outside a workspace [#&#8203;1617](https://github.com/pnpm/pnpm/issues/1617). - The `[<since>]` filter selector now compares against the commit where the current branch forked from `<since>`. Projects changed only by newer commits on `<since>` are no longer selected. Uncommitted changes are still included. In a shallow clone without that commit, pnpm compares against `<since>` directly, as before [#&#8203;9907](https://github.com/pnpm/pnpm/issues/9907). - `--filter "[<since>]"` now selects workspace packages when dependency versions change in a catalog in `pnpm-workspace.yaml` [#&#8203;8718](https://github.com/pnpm/pnpm/issues/8718). It also selects projects that files were moved out of when git detects the move as a rename [#&#8203;15481](https://github.com/pnpm/pnpm/issues/15481). - `--filter` now evaluates selectors in order, so later inclusion filters can re-include packages that an earlier exclusion filter excluded [#&#8203;9354](https://github.com/pnpm/pnpm/issues/9354). - Directory filters such as `--filter=./packages/*` now select projects when the current directory was entered with a lowercase drive letter on Windows, like `c:\repo` [#&#8203;5500](https://github.com/pnpm/pnpm/issues/5500). ##### Custom modulesDir - `pnpm run`, `pnpm exec`, `pnpm version` hooks, and the lifecycle scripts a project runs during install now find commands in a custom `modulesDir`, and bin shims resolve dependency paths there [#&#8203;3604](https://github.com/pnpm/pnpm/issues/3604). Project `.hooks` scripts are read from the configured modules directory. Installs resolved by pnpr now preserve configured modules and executable directories. `pnpm bin` now reports the configured executable directory. In a workspace whose projects keep their own lockfiles, a `packageConfigs` entry that gives one project its own `modulesDir` is followed too. - Tools installed in a custom `modulesDir` can load CommonJS plugins installed there, the same way they would from `node_modules`. When executables are symlinks, as with `preferSymlinkedExecutables` or the hoisted linker, this works for `pnpm run`, `pnpm exec`, `pnpm version` hooks, and the lifecycle scripts a project runs during install. A symlinked tool started directly from a shell does not get it. Paths containing the platform path-list separator do not receive this fallback. `extendNodePath: false` disables this fallback [#&#8203;3604](https://github.com/pnpm/pnpm/issues/3604). - A repeat `pnpm install` in a workspace with a custom `modulesDir` now takes the up-to-date fast path. Before, pnpm looked for each workspace project's dependencies in `node_modules` and ran a full install every time. ##### Adding, updating, and removing dependencies - `pnpm add` now keeps the specifier a `readPackage` hook provides when the hook rewrites the requested one. When the hook removes the dependency instead, the add skips it and reports why. Previously the add wrote the request either way, and the hook undid it on the next read, so `pnpm install --frozen-lockfile` failed [#&#8203;15156](https://github.com/pnpm/pnpm/issues/15156). - `pnpm add` now saves changes to `package.json` before running lifecycle scripts, so a postinstall script failure leaves the added dependency in `package.json` [#&#8203;8627](https://github.com/pnpm/pnpm/issues/8627). - `pnpm add` now saves the requested exact version when adding a dependency, even when the manifest already contains a version range [#&#8203;6040](https://github.com/pnpm/pnpm/issues/6040). - `pnpm add` and `pnpm install` keep an empty `peerDependencies`, `dependencies`, `devDependencies`, or `optionalDependencies` field that was already in `package.json`. pnpm still drops such a field when it removes the last entry itself, as `pnpm remove` does [#&#8203;5096](https://github.com/pnpm/pnpm/issues/5096). - Added a `--peer` flag to `pnpm update` to update ranges in `peerDependencies` [#&#8203;8081](https://github.com/pnpm/pnpm/issues/8081). - `pnpm update` now keeps a version range whose shape has no save prefix, such as `<= 3.0.0` or `>=1.0.0 <2.0.0`, when the updated version still satisfies it. Before, `<= 3.0.0` became `^3.0.0` [#&#8203;6714](https://github.com/pnpm/pnpm/issues/6714). - `pnpm update <name>` now updates a peer dependency that pnpm installed automatically [#&#8203;10486](https://github.com/pnpm/pnpm/issues/10486). - `pnpm update <pkg>` now moves a package off a locked version the registry no longer serves, such as an unpublished release. The lockfile check for supply-chain policies such as `minimumReleaseAge` used to reject that version before the update could replace it [#&#8203;9953](https://github.com/pnpm/pnpm/issues/9953). - `pnpm update --prod` no longer installs devDependencies when run in a project installed with `--prod` [#&#8203;8038](https://github.com/pnpm/pnpm/issues/8038). - `pnpm update --interactive --workspace` now allows external dependencies to be updated. - `pnpm outdated` and `pnpm update` now apply `minimumReleaseAge` to GitHub Actions. `minimumReleaseAgeExclude` entries match action names such as `actions/checkout` [#&#8203;13923](https://github.com/pnpm/pnpm/issues/13923). - `pnpm remove` now runs the project's own `preuninstall`, `uninstall`, and `postuninstall` scripts. `preuninstall` and `uninstall` run before dependencies are unlinked. A failure in either stage aborts the removal. `postuninstall` runs after unlinking completes. The `ignoreScripts` setting and `--lockfile-only` skip all three stages [#&#8203;3276](https://github.com/pnpm/pnpm/issues/3276). - `pnpm remove -r` now fails if any requested dependency is absent from all selected workspace projects. Validation respects `--save-prod`, `--save-dev`, and `--save-optional` and completes before modifying project manifests [#&#8203;2319](https://github.com/pnpm/pnpm/issues/2319). - `pnpm remove` now accepts `--trust-lockfile` and `--no-trust-lockfile` to control supply-chain policy checks while removing a package [#&#8203;14406](https://github.com/pnpm/pnpm/issues/14406). - `pnpm unlink` now removes the `link:` dependency that `pnpm link <dir>` added to `package.json`. The linked package is removed from `node_modules` and the lockfile. A `link:` dependency to another directory is kept [#&#8203;4219](https://github.com/pnpm/pnpm/issues/4219). - `minimumReleaseAgeExcludePrune` and `trustPolicyExcludePrune` now work in workspaces with `shared-workspace-lockfile=false`. Once every project has been installed, pnpm drops an entry only if no project lockfile records it. Undecided `allowBuilds` entries are pruned the same way [#&#8203;14612](https://github.com/pnpm/pnpm/issues/14612). - `pnpm import` now converts dependencies that use Yarn's `patch:` protocol. The dependency keeps the version it patches, and the patch file is added to `patchedDependencies` in `pnpm-workspace.yaml`. If the patch file is missing, pnpm prints a warning and imports the dependency without the patch [#&#8203;10278](https://github.com/pnpm/pnpm/issues/10278). - `pnpm import` in a workspace now keeps the versions pinned by the root `yarn.lock`, `package-lock.json`, or `npm-shrinkwrap.json` when another workspace project's range allows a newer version. Before, the root project got the newest version in its range [#&#8203;4385](https://github.com/pnpm/pnpm/issues/4385). - `pnpm patch-commit` now resolves default patch directory locations when passed a package name or package specifier (such as `pnpm patch-commit <pkg>` or `pnpm patch-commit <pkg>@<version>`). - `pnpm patch-commit` now updates the lockfile snapshot and prunes removed dependencies when the patch modifies `package.json` [#&#8203;6866](https://github.com/pnpm/pnpm/issues/6866). - `pnpm patch-commit` now falls back to copying package files when hard linking fails. - `make-dedicated-lockfile` no longer removes fields such as `main` and `types` from the `publishConfig` of the project's `package.json`. It now restores `package.json` when it cannot move the original `node_modules` back to its place. The error then names `.tmp_node_modules`, where the original `node_modules` was left. The command refuses to run while that directory exists, so a retry cannot overwrite it. ##### Running scripts and commands - A script that pnpm runs without a terminal now ends when pnpm itself is killed. Killing pnpm's process group, as Playwright's `webServer` does to stop the command it started, used to leave the script running and holding the caller's output pipes open [#&#8203;15555](https://github.com/pnpm/pnpm/issues/15555). - `pnpm --filter <project> <command>` and `pnpm -r <command>` now run a command installed in the selected projects' dependencies when none of them has a script by that name. This matches `pnpm <command>` in a single project. `pnpm run` with `--filter` or `-r` still reports the missing script [#&#8203;10151](https://github.com/pnpm/pnpm/issues/10151). - `pnpm exec` and `pnpm dlx` now set `npm_execpath`, `INIT_CWD`, `npm_node_execpath`, and `NODE` for child processes [#&#8203;7037](https://github.com/pnpm/pnpm/issues/7037). Scripts that `pnpx` and `pnx` run now get pnpm itself as `npm_execpath`. A script that ran `$npm_execpath install` there ran `pnpm dlx install`. - `pnpm exec` now sets the `PWD` environment variable to the directory the command runs in. Shells and tools that read `PWD` now report the logical path of a workspace package reached through a symlink [#&#8203;1550](https://github.com/pnpm/pnpm/issues/1550). - A script that runs `pnpm run` no longer adds duplicate `node_modules/.bin` and `node-gyp-bin` entries to `PATH` [#&#8203;5352](https://github.com/pnpm/pnpm/issues/5352). - Concurrent `pnpm run` and `pnpm exec` commands now serialize their dependency installs [#&#8203;14551](https://github.com/pnpm/pnpm/issues/14551). - `pnpm run --recursive` no longer reports interrupted scripts as lifecycle failures after `Ctrl+C`. - `pnpm restart` now runs the "stop" and "start" scripts when the package has no "restart" script. Previously it ran "stop" and then failed with "Missing script: restart" [#&#8203;4750](https://github.com/pnpm/pnpm/issues/4750). - `pnpm install-test` now accepts `--no-bail` when executed directly and in recursive runs [#&#8203;3777](https://github.com/pnpm/pnpm/issues/3777). - `pnpm dlx` now keeps a separate cache entry for each Node.js major version. A package built under one Node.js major version, such as a native addon, is no longer reused under another [#&#8203;8611](https://github.com/pnpm/pnpm/issues/8611). - A `runtime:` version range that contains `||` or a space, such as a `devEngines.runtime` version of `^22.18.0 || ^24.0.0`, now installs the requested runtime. pnpm used to install the npm package with the same name, such as `node` [#&#8203;14817](https://github.com/pnpm/pnpm/issues/14817). - When the configured `scriptShell` does not exist, running a script now fails with an error that names the shell. Previously pnpm printed only an exit code or the package directory [#&#8203;7562](https://github.com/pnpm/pnpm/issues/7562). - If a script is killed by a signal that pnpm survives, such as SIGPIPE, the error now names the signal: `Command failed with signal SIGPIPE.` [#&#8203;9821](https://github.com/pnpm/pnpm/issues/9821). ##### Publishing, packing, and deploying - `pnpm publish` now resolves `workspace:` dependencies from workspace manifests when `node_modules` is not installed. Previously, publishing without `node_modules` failed with `ERR_PNPM_CANNOT_RESOLVE_WORKSPACE_PROTOCOL` [#&#8203;6567](https://github.com/pnpm/pnpm/issues/6567). - `pnpm publish` now honors `publishConfig["@scope:registry"]` for a package in that scope. It takes precedence over the registry set for the same scope in `.npmrc` and over `publishConfig.registry` [#&#8203;12071](https://github.com/pnpm/pnpm/issues/12071). - `pnpm pack` and `pnpm publish` now include bundled dependencies when using the isolated linker. This covers workspace packages and the dependencies of each bundled package. Bundled dependencies are also included when `publishConfig.directory` selects a build directory [#&#8203;1643](https://github.com/pnpm/pnpm/issues/1643). - `pnpm pack`, `pnpm deploy`, and installs of local directory dependencies now keep symlinks that point to files or directories included in the package. `pnpm pack` leaves out symlinks that point outside the package [#&#8203;8208](https://github.com/pnpm/pnpm/issues/8208). - `pnpm pack` now honors the `files` field of `package.yaml` and `package.json5` manifests. Git-hosted and injected local dependencies that use these manifests now honor it too [#&#8203;7906](https://github.com/pnpm/pnpm/issues/7906). The archive includes exactly one `package.json` when the project uses an alternative manifest format, even when `.npmignore` or `files` excludes the source file. - `pnpm pack` now preserves file executable permissions in the packed tarball when source files are executable on disk. - `pnpm publish` and `pnpm pack` now report a missing `version` or `name` field on a workspace dependency. Previously, pnpm reported that the dependency was not installed [#&#8203;4164](https://github.com/pnpm/pnpm/issues/4164). - `pnpm publish` and `pnpm pack` now report an error when a bin script has a shebang line ending with CRLF [#&#8203;7311](https://github.com/pnpm/pnpm/issues/7311). - `pnpm deploy` now copies the `packageManager` and `devEngines.packageManager` fields of the workspace root `package.json` into the deployed `package.json`, unless the deployed project pins a package manager itself [#&#8203;9079](https://github.com/pnpm/pnpm/issues/9079). - `pnpm deploy` now puts the virtual store at `virtualStoreDir`, resolved against the deploy directory. A shared-lockfile deploy records `virtualStoreDir` in the deployed `pnpm-workspace.yaml`. With the global virtual store enabled or an absolute `virtualStoreDir`, the deploy still uses `node_modules/.pnpm` [#&#8203;8787](https://github.com/pnpm/pnpm/issues/8787). - `pnpm deploy` now respects `--package-import-method` passed on the command line and reports the package import method correctly [#&#8203;7593](https://github.com/pnpm/pnpm/issues/7593). - `pnpm deploy` no longer triggers an install when running scripts in a read-only deployed filesystem [#&#8203;11617](https://github.com/pnpm/pnpm/issues/11617). - A legacy `pnpm deploy` with `node-linker=hoisted` now puts the deployed project's direct dependencies at the top of the deployed `node_modules` [#&#8203;9671](https://github.com/pnpm/pnpm/issues/9671). - `pnpm deploy --legacy` no longer rewrites `node_modules/.pnpm-workspace-state-v1.json` in the source workspace. The next `verifyDepsBeforeRun` check there reported the workspace as out of date [#&#8203;15352](https://github.com/pnpm/pnpm/issues/15352). ##### Manifests and configuration files - Fixed `pnpm version` failing on projects using a `package.yaml` manifest. Fixed `pnpm init` creating an extra `package.json` when `package.yaml` is already present. - pnpm now preserves CRLF line endings when it modifies project manifests. - `pnpm version` now applies pending bumps to private workspace packages. A private package's changelog is written to its committed `CHANGELOG.md`, also when `versioning.changelog.storage` is `registry` [#&#8203;13736](https://github.com/pnpm/pnpm/issues/13736), [#&#8203;13519](https://github.com/pnpm/pnpm/issues/13519). - `pnpm change check` now validates the pending change intents in `.changeset/`. It fails when an intent names a package that is not in the workspace or cannot be released. - `.npmrc` files now support npm's `${VAR?}` placeholder. It expands to the value of `VAR`, or to an empty string without a warning when `VAR` is unset [#&#8203;14404](https://github.com/pnpm/pnpm/issues/14404). - pnpm now expands environment variables in `_auth.authToken` values loaded from global `config.yaml` and `pnpm_config__auth` [#&#8203;12828](https://github.com/pnpm/pnpm/issues/12828). - pnpm now warns when an empty environment variable removes an `.npmrc` authentication token. Authentication environment warnings now name the affected key [#&#8203;4806](https://github.com/pnpm/pnpm/issues/4806). - pnpm now keeps the configured default registry when `_auth` holds credentials for several registries and some of those registries serve package scopes. Lockfile verification checks a tarball hosted on a scoped registry against that registry's metadata, unless the package's own scope has a registry assigned [#&#8203;15530](https://github.com/pnpm/pnpm/issues/15530). - pnpm now treats a missing global `config.yaml`, `auth.ini`, or other optional config file as absent in Node.js-compatible runtimes such as StackBlitz WebContainers. Commands such as `pnpm --version` failed there with `ENOENT` [#&#8203;14030](https://github.com/pnpm/pnpm/issues/14030). - `pnpm login` now logs back in to an existing user on registries without web login, such as verdaccio. The classic login request sends the username and password as basic auth, as `npm login` does [#&#8203;12055](https://github.com/pnpm/pnpm/issues/12055). - `pnpm doctor` now checks the configured default registry and sends its credentials. It used to always ping `https://registry.npmjs.org/` [#&#8203;15618](https://github.com/pnpm/pnpm/issues/15618). ##### Global packages, pnpm versions, and runtimes - Global commands such as `pnpm add --global`, `pnpm list --global`, and `pnpm bin --global` now run with the pnpm you invoked, even in a project that pins another pnpm version. Previously, a pin with `onFail: "download"` switched them to the pinned pnpm, and a pinned pnpm 10 or older failed because its global bin directory was not in `PATH` [#&#8203;14531](https://github.com/pnpm/pnpm/issues/14531). - `pnpm add -g`, `pnpm update -g`, and `pnpm remove -g` now recover a global package group whose entire `node_modules` directory was deleted. `pnpm remove -g` leaves such a group's command shims in the global bin directory [#&#8203;15093](https://github.com/pnpm/pnpm/issues/15093). These commands no longer fail with `ERR_PNPM_PACKAGE_MANIFEST_IO_ERROR` when another global package's link into the store dangles, for example after the store was pruned. The pnpm install script failed the same way on such a machine. - `pnpm update --global` now skips a global package installed from a `file:` path that no longer exists, prints a warning, and updates the remaining global packages. Previously the whole update failed with `ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND` [#&#8203;12533](https://github.com/pnpm/pnpm/issues/12533). - `pnpm update -g` no longer asks more than once for approval of the same immature `name@version` when `minimumReleaseAgeStrict` is enabled [#&#8203;15091](https://github.com/pnpm/pnpm/issues/15091). - `pnpm self-update` run in a project that pins pnpm through `packageManager` or `devEngines.packageManager` now also updates the global pnpm, as it does outside a project [#&#8203;14747](https://github.com/pnpm/pnpm/issues/14747). - `pnpm self-update` no longer leaves the previous pnpm in the global packages when it was installed as `@pnpm/exe`. `pnpm ls -g` now lists a single pnpm [#&#8203;14709](https://github.com/pnpm/pnpm/issues/14709). - `pnpm setup` no longer deletes aliases and other lines that sit between a `# pnpm` comment and the pnpm block in a shell startup file [#&#8203;7067](https://github.com/pnpm/pnpm/issues/7067). - `pnpm env remove` now cleans up dangling Node.js executables and symlinks. Surviving global commands remain intact. - Node.js runtime resolution now supports Windows ARM64. Node.js 20 and newer resolve native `win-arm64` builds, and older versions fall back to `win-x64` under emulation [#&#8203;7123](https://github.com/pnpm/pnpm/issues/7123). ##### Windows and WSL - `pn`, `pnpx`, `pnx`, and `pnpm` now run when Git Bash, MSYS2, or Cygwin launches them through a Windows path such as `C:\Users\me\node_modules\pnpm\pn`. The aliases used to fail to find the pnpm installed beside them, or hand the call to an unrelated one [#&#8203;14884](https://github.com/pnpm/pnpm/issues/14884). - Fallback `.cmd` and `.ps1` Windows wrappers in `@pnpm/exe` now propagate the exit status of the invoked `pnpm` command [#&#8203;14826](https://github.com/pnpm/pnpm/issues/14826). - On Windows, bin shims run from Git Bash, MSYS2, or Cygwin now pass `NODE_PATH` to Node.js as Windows paths. A project installed from cmd or PowerShell gave its bins a `NODE_PATH` under the Git install directory when they ran from Git Bash. Installing again replaces the shims already in `node_modules` [#&#8203;3360](https://github.com/pnpm/pnpm/issues/3360). - `pnpm install` in WSL now waits out Windows file locks on a Windows drive such as `/mnt/c`, as it already does on Windows. Before, an antivirus or indexer scan holding a file open could fail the install with `EACCES` [#&#8203;6155](https://github.com/pnpm/pnpm/issues/6155). - On Windows, pnpm now retries saving `pnpm-lock.yaml` for up to a minute while another process holds the file open. The save used to fail at once with `EPERM`, `EBUSY`, or "Access is denied" [#&#8203;9461](https://github.com/pnpm/pnpm/issues/9461). - On Windows, pnpm now fails within about a second when it cannot move a `node_modules` directory installed by another package manager because a file in it is in use. The error names the directory and suggests stopping the process that uses it. pnpm used to retry for a minute and then print a raw `EPERM` stack trace [#&#8203;7505](https://github.com/pnpm/pnpm/issues/7505). - pnpm now escapes trailing dots and spaces in `node_modules/.pnpm` directory names. Windows strips these characters, so a dependency such as `"parent-pkg": "file:../"` created a directory that could not be deleted or failed to install [#&#8203;8101](https://github.com/pnpm/pnpm/issues/8101). - `pnpm install` now resolves local tarballs specified with bare UNC paths on Windows [#&#8203;1669](https://github.com/pnpm/pnpm/issues/1669). - pnpm now recognizes local paths with forward slashes on Windows. - On Windows, `pnpm add` and `pnpm update` now write relative `file:` and `link:` specifiers with forward slashes to `package.json` and the lockfile. They used to write backslashes, so the same project produced different files on Windows and on other systems [#&#8203;7497](https://github.com/pnpm/pnpm/issues/7497), [#&#8203;9687](https://github.com/pnpm/pnpm/issues/9687). - Fixed scripts failing with errors such as `'an-compile' is not recognized` when `scriptShell` is set to `cmd.exe` on Windows [#&#8203;7181](https://github.com/pnpm/pnpm/issues/7181). ##### Inspecting dependencies - `pnpm audit` and `pnpm audit signatures` now check only the dependencies of the projects selected by `--filter`, `--filter-prod`, or `--workspace-root`. The filter used to be ignored, so a filtered audit reported the whole workspace [#&#8203;10982](https://github.com/pnpm/pnpm/issues/10982). - `pnpm audit` now lists at least one dependency path from every workspace project that depends on a vulnerable package. Before, a project whose dependency was reached through more than 100 paths filled the path list, and other projects that depend on the same package were left out [#&#8203;12200](https://github.com/pnpm/pnpm/issues/12200). - `pnpm audit --fix=update` now fixes vulnerabilities in dependencies declared through an npm alias. A specifier such as `"foo": "npm:vulnerable-pkg@1.0.0"` moves to the patched version and keeps the alias. Versions pinned with a leading `=` are fixed as well [#&#8203;15155](https://github.com/pnpm/pnpm/issues/15155). - `pnpm audit --fix` now prunes redundant overrides when one vulnerable range is a subset of another for the same package [#&#8203;8577](https://github.com/pnpm/pnpm/issues/8577). - Running `pnpm list` inside a workspace package without `--recursive` or a filter now lists only the current package [#&#8203;14494](https://github.com/pnpm/pnpm/issues/14494). `pnpm licenses list` does the same. Use `--recursive` or `--filter` to list the licenses of other workspace projects [#&#8203;5689](https://github.com/pnpm/pnpm/issues/5689). - `pnpm list --only-projects` now prints every project selected with `--filter` or `--recursive`, including a project that has no workspace dependencies [#&#8203;9770](https://github.com/pnpm/pnpm/issues/9770). It also lists the workspace projects when `sharedWorkspaceLockfile` is `false` [#&#8203;7151](https://github.com/pnpm/pnpm/issues/7151), and a project that sets `publishConfig.directory` [#&#8203;10635](https://github.com/pnpm/pnpm/issues/10635). It no longer reports packages in `node_modules` that are missing from the lockfile [#&#8203;9528](https://github.com/pnpm/pnpm/issues/9528). - `pnpm licenses list` failed or reported nothing in a workspace with `sharedWorkspaceLockfile: false`. It now reads the lockfile of each selected project [#&#8203;10140](https://github.com/pnpm/pnpm/issues/10140). - With `nodeLinker: hoisted`, `pnpm licenses list` reported paths under `node_modules/.pnpm` that do not exist. It now reports the directory where the hoisted linker placed each package [#&#8203;8589](https://github.com/pnpm/pnpm/issues/8589). - `pnpm outdated` and `pnpm -r outdated` now fail with `ERR_PNPM_NO_PACKAGE_IN_DEPENDENCIES` when a requested package selector does not match any dependency in the inspected projects [#&#8203;2319](https://github.com/pnpm/pnpm/issues/2319). - `pnpm -r outdated --json` now includes every outdated workspace dependency when multiple projects depend on different versions or dependency types of the same package. Such a package is keyed by its current version and dependency type, for example `vue@2.7.14 (dev)` [#&#8203;7693](https://github.com/pnpm/pnpm/issues/7693). - `pnpm sbom` filtered to a single workspace project no longer replaces the project's own `license` or `bugs` field with the workspace root's value when the project's value is blank. The same applies to an `author`, `description`, `license`, `repository`, or `bugs` field set to `null` [#&#8203;14882](https://github.com/pnpm/pnpm/issues/14882). - `pnpm store status` no longer reports packages with build or postinstall scripts as modified in the store. When packages were mutated, it now lists only those packages and no longer suggests running `pnpm install --force` [#&#8203;919](https://github.com/pnpm/pnpm/issues/919). - `pnpm peers check` and the `ERR_PNPM_PEER_DEP_ISSUES` error now group peer dependency issues under the workspace project they were found in [#&#8203;15351](https://github.com/pnpm/pnpm/issues/15351). - The `pnpm:peer-dependency-issues` log event, which `--reporter ndjson` prints, no longer lists peers silenced by `peerDependencyRules.ignoreMissing` under `conflicts` or `intersections` [#&#8203;8295](https://github.com/pnpm/pnpm/issues/8295). ##### Output and messages - The error for an incompatible pnpm-lock.yaml now reports the lockfileVersion the file was generated with and the lockfileVersion the current pnpm supports. The error also warns that recreating the lockfile with `--force` may break the application and suggests installing the pnpm version that generated the lockfile [#&#8203;848](https://github.com/pnpm/pnpm/issues/848). - When the registry stops sending data for longer than `fetchTimeout`, pnpm now reports that the metadata or tarball request timed out. Previously the error did not mention the timeout [#&#8203;3646](https://github.com/pnpm/pnpm/issues/3646). - Resolution no longer logs an error when a package metadata request fails and resolution succeeds via cached metadata [#&#8203;2522](https://github.com/pnpm/pnpm/issues/2522). - The ignored build scripts warning and the update notice are printed as plain lines when output is not a terminal, in CI, or with `--reporter append-only`. They were drawn inside a box that broke apart in CI logs [#&#8203;9421](https://github.com/pnpm/pnpm/issues/9421). - `pnpm run` with `--loglevel` set to `warn`, `error`, or `silent` (or the same `loglevel` setting) no longer prints the `$ <command>` line before a script, nor the summary of the install that `verifyDepsBeforeRun` runs first. Both are info-level output [#&#8203;8944](https://github.com/pnpm/pnpm/issues/8944). - `pnpm add` now warns when replacing an existing dependency with a specifier pointing to a different source [#&#8203;14869](https://github.com/pnpm/pnpm/issues/14869). - `pnpm update` no longer warns "Skip adding ... to the default catalog" for a dependency that already uses `catalog:` [#&#8203;13715](https://github.com/pnpm/pnpm/issues/13715). - `pnpm remove --help` no longer shows a `[@<version>]` suffix in its usage line. The command accepts package names only [#&#8203;7751](https://github.com/pnpm/pnpm/issues/7751). - Bash completion now completes script names that contain a colon, such as `pnpm run test:u` to `pnpm run test:unit` [#&#8203;5482](https://github.com/pnpm/pnpm/issues/5482). <!-- 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 --> ### [`v11.27.1`](https://github.com/pnpm/pnpm/releases/tag/v11.27.1): pnpm 11.27.1 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.27.0...v11.27.1) #### Patch Changes - `pn`, `pnpx`, and `pnx` now run the pnpm installed alongside them. They used to look pnpm up on `PATH`. That failed when the directory holding them was not on `PATH`, and it silently handed the call to an unrelated pnpm when one came first there [#&#8203;14803](https://github.com/pnpm/pnpm/issues/14803). - The `@zkochan/cmd-shim` package is now available as `@pnpm/bins.cmd-shim`. - `pnpm cache list-registries` now prints the registry URL, matching `pnpm cache view`. It printed `https%3A+registry.npmjs.org` before and prints `https://registry.npmjs.org/` now [#&#8203;15046](https://github.com/pnpm/pnpm/issues/15046). - `pnpm deploy` no longer installs the dependencies of the workspace root project into the deploy directory [#&#8203;6437](https://github.com/pnpm/pnpm/issues/6437). - Install warnings no longer carry the text of a package's deprecation notice. The warning names the deprecated package and version, and the `pnpm:deprecation` event no longer carries the notice either. `pnpm view` still shows it on request. A deprecation warning now names the newest version of the package that is not deprecated, and says when reaching it means widening the range you declared: ``` WARN deprecated foo@1.0.0. 2.3.1 is not deprecated, outside the range you declared. ``` pnpm works this out from the metadata it already fetched, so it costs no extra request. An install that reuses the lockfile without fetching metadata names no version. pnpm strips control characters from the package name and version in a deprecation warning, and from the notice `pnpm outdated --long` prints. The text sanitizer now also strips the Unicode line and paragraph separators U+2028 and U+2029. - `pnpm exec <command>` and `pnpm <command>` run from a subdirectory of a project now find the executables installed in the project's `node_modules/.bin`. The command still runs in the subdirectory. `PNPM_PACKAGE_NAME` names the project [#&#8203;5068](https://github.com/pnpm/pnpm/issues/5068). - `pnpm exec` and `pnpm dlx` now wait for the command to finish shutting down after `Ctrl+C`. A signal sent to pnpm alone now reaches the command, the way it does with `pnpm run`. pnpm used to exit on the interrupt and terminate the command while it was still shutting down [#&#8203;7374](https://github.com/pnpm/pnpm/issues/7374). - Warnings about ignored environment variables in project `.npmrc` credentials now link to the npmrc documentation [pnpm/pnpm#15051](https://github.com/pnpm/pnpm/issues/15051). - `pnpm audit --interactive --fix=update` no longer opens a second prompt for selecting dependencies to update [#&#8203;14927](https://github.com/pnpm/pnpm/issues/14927). - Fixed `pnpm dedupe` requiring a second pass after bumping a direct dependency in `package.json` [pnpm/pnpm#14987](https://github.com/pnpm/pnpm/issues/14987). - `pnpm deploy` now writes plain versions for registry dependencies with peer dependencies in the deployed `package.json`. The deployed lockfile retains the resolved peer bindings. npm aliases keep their target package names [#&#8203;14873](https://github.com/pnpm/pnpm/issues/14873). - `pnpm publish` now allows a detached Git HEAD in CI, including checkouts of release tags. The working tree must still be clean. Branch and remote-history checks still apply when HEAD is attached [pnpm/pnpm#5894](https://github.com/pnpm/pnpm/issues/5894). - `pnpm dlx` and `pnx` now prompt to approve dependency build scripts in interactive terminals. Cached packages with pending builds also prompt for approval. Without an interactive terminal, use `--allow-build` to allow the required builds. Fixes [pnpm/pnpm#14943](https://github.com/pnpm/pnpm/issues/14943). - `pnpm install --force` now removes obsolete dependency links inside virtual-store packages when their dependencies change. Invalid dependency names are ignored during obsolete-link cleanup [#&#8203;15039](https://github.com/pnpm/pnpm/issues/15039). - `pnpm add -g` and `pnpm update -g` now ignore incomplete unrelated global package groups when every command from the replaced group is retained. Operations that could remove a global command still require complete ownership information. - Resolving a Node.js runtime now fails when unofficial-builds.nodejs.org cannot be reached. pnpm used to ignore that failure and leave the musl builds out of `pnpm-lock.yaml`. `pnpm update` then wrote a different lockfile on a machine whose network blocks the mirror [pnpm/pnpm#14813](https://github.com/pnpm/pnpm/issues/14813). - pnpm now deduplicates a package whose child dependency resolved an optional peer in one workspace project but not in another. Two copies of `next` could appear when only some projects could reach `styled-jsx`'s optional `babel-plugin-macros` peer [#&#8203;14800](https://github.com/pnpm/pnpm/issues/14800). - Fixed shell completion of package scripts for `pnpm run` and `pnpm run-script` [pnpm/pnpm#15034](https://github.com/pnpm/pnpm/issues/15034). Bash completion now preserves literal script names containing glob characters and shell punctuation in pnpm v11 and v12. - `pnpm sbom` now publishes a valid URL in the CycloneDX `externalReferences[].url` and the SPDX `homepage`. An npm shorthand such as `vercel/ms` or `gitlab:group/subgroup/project` is expanded to the `git+https` URL npm derives for it. An scp-style remote such as `git@github.com:vercel/ms.git` is expanded the same way. Any other URL is published in its normalized form, without embedded credentials. A value that names no repository, an email address for example, is left out. pnpm used to publish the raw value, so a shorthand produced a URL that consumers such as Dependency-Track reject [pnpm/pnpm#14773](https://github.com/pnpm/pnpm/issues/14773). - `pnpm setup` now describes the displayed configuration changes as "the following configuration changes." - `pnpm --version` now reports why the pnpm version a project pins cannot be installed or recorded, then prints the version of the running CLI. It used to fail, which made the command unusable where the filesystem is read-only. `pnpm --version` also honors `--store-dir` and its `--store` alias now [#&#8203;14831](https://github.com/pnpm/pnpm/issues/14831). - `pnpm install --force` now reinstalls dependencies when the manifest and lockfile are unchanged. It previously reported "Already up to date" without reinstalling. Files changed in `node_modules` are restored when the store content is intact. Combining `--force` with `--frozen-store` now reports a configuration conflict on repeat installs [#&#8203;919](https://github.com/pnpm/pnpm/issues/919). - `pnpm install` now installs git-hosted dependencies without preparing them when their builds are explicitly denied by `allowBuilds`. Dependencies that require preparation still need an explicit allow or deny decision [pnpm/pnpm#10522](https://github.com/pnpm/pnpm/issues/10522). - `pnpm runtime set` and `pnpm env use` now use the pnpm version that started the command. They could run a different installed pnpm when the command was started through Corepack or another wrapper. - The install summary now names the version each dependency resolved to when `node-linker` is `hoisted`. It also lists what an install restores after `node_modules` is deleted, and both sides of a version change. The summary showed the range recorded in `package.json`, or nothing at all [#&#8203;15161](https://github.com/pnpm/pnpm/issues/15161). - The `@pnpm/npm-lifecycle` package is now available as `@pnpm/exec.npm-lifecycle`. - Fixed `minimumReleaseAge` making pnpm download a package's full metadata again on every install. The cached copy carried a validator the registry could not match, so pnpm could never revalidate it [pnpm/pnpm#15103](https://github.com/pnpm/pnpm/issues/15103). - pnpm now measures a `pnpm.overrides` entry written as a bare path, such as `./local-dep`, from the directory holding `pnpm-workspace.yaml`. It used to be measured from each package the override rewrote, so the dependency linked to a directory that does not exist [#&#8203;11131](https://github.com/pnpm/pnpm/issues/11131). - pnpm now preserves scalar YAML anchors and aliases when editing `pnpm-workspace.yaml`. Removing the entry that defines an anchor keeps surviving aliases valid. Entries updated to different values are written separately [#&#8203;8245](https://github.com/pnpm/pnpm/issues/8245). - pnpm now preserves comments and existing key order when updating `package.yaml`. New keys are appended to their mapping [pnpm/pnpm#2008](https://github.com/pnpm/pnpm/issues/2008). - `pnpm install --prod` no longer downloads the registry packages that only a devDependency reaches [#&#8203;881](https://github.com/pnpm/pnpm/issues/881). - `pnpm update --global` no longer reinstalls a global package when its dependency graph resolves to what is already installed. It reports `Already up to date` [pnpm/pnpm#12002](https://github.com/pnpm/pnpm/issues/12002). - The `minimumReleaseAge` approval prompt now counts and displays each package version once [pnpm/pnpm#15083](https://github.com/pnpm/pnpm/issues/15083). - `pnpm run` no longer sends a script a second `SIGINT` when `Ctrl+C` is pressed in a terminal. A script that shuts down on the first `SIGINT` and exits at once on a second used to die before its shutdown finished [#&#8203;7374](https://github.com/pnpm/pnpm/issues/7374). - pnpm now reads a `pnpm-workspace.yaml` whose `tasks` section uses a setting only pnpm 12 acts on, such as `concurrencyGroup`. A task's unrecognized fields are ignored, unless the field only differs in case from `concurrency` or `dependsOn`, which pnpm reports as a typo. The warning about unrecognized top-level settings now names `cargo`, `concurrencyGroups`, and `pipelines` as pnpm 12 settings. - `pnpm -r list --json` now prints one JSON array. It printed a separate array for each project when `sharedWorkspaceLockfile` was `false`, so the output could not be parsed. `pnpm -r list` now reads each project's own modules directory when the projects keep their own lockfiles, so `--long` and `--parseable` report the packages that project installed [#&#8203;15011](https://github.com/pnpm/pnpm/issues/15011). - A signal sent to pnpm while it runs without a terminal, as a container runtime or a service manager does, now reaches the script even when the shell running it stays the script's parent. pnpm then waits for the script to finish shutting down. Such a signal used to end the shell at once or stay with it, and the script was never told to stop [#&#8203;7374](https://github.com/pnpm/pnpm/issues/7374). - Fixed `minimumReleaseAge` being skipped for packages served by a registry that returns the same ETag for abbreviated and full package metadata [pnpm/pnpm#14925](https://github.com/pnpm/pnpm/issues/14925). - `pnpm install` now returns "Already up to date" in a workspace where `dedupeDirectDeps` left a project without a `node_modules` directory of its own. Such a project forced a full install on every run. - Installs in different projects that share a global virtual store no longer fail on Windows with `Access is denied` while repairing the same slot [#&#8203;15114](https://github.com/pnpm/pnpm/issues/15114). - `pnpm sbom` now emits a license value as a CycloneDX expression only when it is a valid SPDX license expression. Anything else is emitted as a CycloneDX license name [pnpm/pnpm#14786](https://github.com/pnpm/pnpm/issues/14786). - A dependency's own bins can no longer take over another package's bin shim. The POSIX shims pnpm generates used to look up their shell helpers on `PATH`, where a dependency's bins come first [#&#8203;14837](https://github.com/pnpm/pnpm/issues/14837). Reinstalling replaces the shims already in your `node_modules`. On Cygwin, MSYS2, and WSL the shims still take their Windows path conversion from `PATH`, so a dependency can still redirect them there. - POSIX bin shims now convert a Windows-form path such as `C:\node_modules\.bin\tsc` correctly. The shim mangled the backslashes in such a path and could not reach the package it runs. Installing again replaces the shims already in `node_modules` [#&#8203;14867](https://github.com/pnpm/pnpm/issues/14867). - `pnpm pack` now writes tarball entries grouped by file extension and file name, the order npm uses. Packages that ship many same-named files, such as template collections, pack much smaller [#&#8203;14766](https://github.com/pnpm/pnpm/issues/14766). - A command run in a project that the workspace does not include now acts on that project alone. A project is outside the workspace when it has a manifest of its own and no pattern in the `packages` setting selects it, or when a `!` pattern excludes it. A directory with no manifest of its own, such as a package's source directory, still belongs to the workspace. `pnpm install` in an excluded project used to install every project in the workspace [#&#8203;3561](https://github.com/pnpm/pnpm/issues/3561). - POSIX bin shims now take `cygpath` and `wslpath` from the system default path on Cygwin, MSYS2, and WSL2. The shims looked both helpers up on `PATH`, where a dependency's own bins come first, so a dependency could redirect another package's shim. Installing again replaces the shims already in `node_modules` [#&#8203;14866](https://github.com/pnpm/pnpm/issues/14866). - `pnpm update` and `pnpm audit --fix=update` no longer copy dependencies added by `packageExtensions`, a `readPackage` hook, or an override into `package.json`. Those dependencies keep the specifier the hook or override gives them. `pnpm update --latest` no longer resolves past that specifier. `pnpm audit --fix=update` now warns when one of them pins a vulnerable version. The warning points at `pnpm audit --fix` [#&#8203;14928](https://github.com/pnpm/pnpm/issues/14928). <!-- 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 --> ### [`v11.27.0`](https://github.com/pnpm/pnpm/releases/tag/v11.27.0): pnpm 11.27 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.26.0...v11.27.0) #### Minor Changes - `nodeDownloadMirrors` can now be set in the global config file (`config.yaml`) and through the `PNPM_CONFIG_NODE_DOWNLOAD_MIRRORS` environment variable, so a Node.js download mirror can be configured once for a machine instead of in every workspace [#&#8203;12124](https://github.com/pnpm/pnpm/issues/12124), [#&#8203;13611](https://github.com/pnpm/pnpm/issues/13611). ```sh PNPM_CONFIG_NODE_DOWNLOAD_MIRRORS='{"release":"https://npmmirror.com/mirrors/node/"}' ``` - Added a new setting `trustPolicyExcludePrune` (default: `false`). When enabled, `pnpm add`, `pnpm update`, and `pnpm remove` prune the entries of `trustPolicyExclude` in `pnpm-workspace.yaml` that the freshly written lockfile no longer resolves: versions that are gone are dropped (an entry is removed once none of its versions remain), and entries for packages that are no longer in the lockfile are removed too. Name patterns (`@scope/*`) are always kept. The cleanup is skipped when the install's lockfile does not cover the whole workspace (`sharedWorkspaceLockfile: false`), since entries another project still needs would look stale. #### Patch Changes - pnpm now reads the `packageManager`, `devEngines.packageManager` and runtime pins from the workspace root's `package.json` when `lockfileDir` is set. A project that moved its lockfile lost the pins it declared there [#&#8203;14633](https://github.com/pnpm/pnpm/issues/14633). - Fixed `pnpm add -g`, `pnpm update -g`, and `pnpm remove -g` mutating global bins or install directories after only partially reading an installed package group. If any declared package manifest is missing, malformed, or unreadable, pnpm now fails before activation or removal and leaves the existing global installation intact [pnpm/pnpm#13796](https://github.com/pnpm/pnpm/issues/13796). - `fetch-timeout` now limits how long a request may make no progress. The timer restarts on every chunk that arrives. A large download over a slow connection is no longer aborted while data is still coming in. A connection that stops delivering data still fails after `fetch-timeout` [#&#8203;14604](https://github.com/pnpm/pnpm/issues/14604). - `pnpm peers check` no longer reports a peer dependency declared as `workspace:^`, `workspace:~`, or a bare `workspace:` as unmet. pnpm reported these as unmet whatever version the linked workspace project supplied [#&#8203;14770](https://github.com/pnpm/pnpm/issues/14770). - A `readPackage` hook that edits its argument in place no longer changes what a later install in the same command resolves. A `deprecated` notice read from the lockfile no longer carries over to another install either [#&#8203;13988](https://github.com/pnpm/pnpm/issues/13988). - `pnpm install` now auto-installs missing transitive peers when workspace projects share a dependency at different depths. This also removes incomplete duplicate peer contexts from the lockfile. Fixes [pnpm/pnpm#14840](https://github.com/pnpm/pnpm/issues/14840). - GitHub Actions updates now stop if an action reference changes while its versions are being resolved. Unrelated workflow edits are preserved. GitHub Actions homepage links no longer expose server credentials. GitHub server URLs now require HTTPS, with HTTP allowed only for loopback hosts. - `pnpm licenses list` now reports the runtime downloaded through `devEngines.runtime` with `onFail: "download"`. The command previously failed with `ERR_PNPM_UNSUPPORTED_PACKAGE_TYPE` [#&#8203;14172](https://github.com/pnpm/pnpm/issues/14172). - pnpm no longer creates a project `pnpm-lock.yaml` when `devEngines.packageManager.onFail` is `download` and lockfile writing is turned off with `lockfile: false` or `--no-lockfile`. pnpm still switches to the pinned version [#&#8203;14728](https://github.com/pnpm/pnpm/issues/14728). - A `registry` or `@scope:registry` set in an `.npmrc` now wins over the registry a `pnpm login` credential stored in the global `config.yaml` points at. Previously, after logging in to one registry, installs in a project whose `.npmrc` named a private registry went to the logged-in registry instead. They now go to the registry the `.npmrc` names [#&#8203;14614](https://github.com/pnpm/pnpm/issues/14614). - A patch that gives a dependency a `preinstall`, `install`, or `postinstall` script, or a `binding.gyp`, now runs that build. pnpm asks for build approval first, so the package is listed under "Ignored build scripts" until it is allowed to build. pnpm 12 ran nothing, and pnpm 11 ran it without asking [#&#8203;14648](https://github.com/pnpm/pnpm/issues/14648). - Registries that share a host but differ by URL path — one JFrog Artifactory, Nexus, AWS CodeArtifact or GitLab Packages instance serving several repositories — now get a metadata cache directory each. Previously they shared one, so resolving a package from one of them could answer with another's versions, integrity hashes and tarball URLs and fail with `ERR_PNPM_TARBALL_URL_MISMATCH` [#&#8203;13558](https://github.com/pnpm/pnpm/issues/13558). The URL scheme is part of the cache directory name too, so an `http` registry can no longer hand its metadata — which can be rewritten in transit — to a resolution configured for `https` at the same host. The first install after upgrading refetches registry metadata once. The package store is untouched. `pnpm cache view` now labels each entry with the full registry URL. It printed `registry.npmjs.org` before and prints `https://registry.npmjs.org/` now. `pnpm cache list-registries` and `pnpm cache list` print the new directory names. Scripts that parse either command need updating. - Updated the embedded Node.js release keys to the current canonical `nodejs/release-keys` list. - `pnpm sbom` now omits package author fields when the manifest author name is empty or contains only whitespace [pnpm/pnpm#14685](https://github.com/pnpm/pnpm/issues/14685). In a filtered or split workspace run, only a project with no `author` field inherits the workspace root's author. - `pnpm sbom --sbom-format spdx` now writes `creationInfo.created` with whole seconds, such as `2026-09-08T10:38:21Z`. The timestamp carried fractional seconds, which strict SPDX consumers rejected [#&#8203;14684](https://github.com/pnpm/pnpm/issues/14684). - Windows filesystem operations now retry permission errors for up to one second. Permanent permission errors previously delayed failure by a minute. Sharing and lock violations retain their one-minute retry budget [pnpm/pnpm#14682](https://github.com/pnpm/pnpm/issues/14682). - pnpm now writes `node_modules/.package-map.json` only when `nodeExperimentalPackageMap` is enabled. Nothing reads the file without that setting. An install that stops writing the map removes the one a previous install left. - pnpm now unpacks a downloaded runtime archive into a randomly named directory inside the store. It previously used a predictable path, where another user of a shared store could plant a symlink and redirect the write outside the store ([GHSA-vwc7-r8mq-g2x9](https://github.com/advisories/GHSA-vwc7-r8mq-g2x9)). <!-- 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 --> ### [`v11.26.0`](https://github.com/pnpm/pnpm/releases/tag/v11.26.0): pnpm 11.26 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.25.0...v11.26.0) #### Minor Changes - Catalogs can now resolve workspace dependencies through the `workspace:` protocol. - `pnpm remove` and `pnpm update` now accept `--trust-lockfile`, `--no-trust-lockfile`, `--trust-policy`, `--trust-policy-exclude`, and `--trust-policy-ignore-after`. `pnpm remove` checks the whole lockfile against the active policies unless `--trust-lockfile` is set. - Added `pnpm change check` for CI validation of package versions against the `versioning.epics` bands and `versioning.fixed` groups in `pnpm-workspace.yaml`. #### Patch Changes - Fetch and tarball errors and retry logs now hide URL credentials, query strings, and fragments that could expose secrets. - Fixed a race during config dependency updates that could redirect a lockfile write through a symlink [#&#8203;14322](https://github.com/pnpm/pnpm/issues/14322). - `pnpm add --allow-build=!<pkg>` now correctly denies builds, including in global installs. `pnpm approve-builds <pkg>` and `pnpm approve-builds !<pkg>` now save decisions even when the package is not awaiting approval, with a warning [#&#8203;14067](https://github.com/pnpm/pnpm/issues/14067). - Fixed `pnpm audit --fix` failing without a value or when followed by another flag. `pnpm audit --fix=override` now respects `saveExact` and `savePrefix` when writing overrides [#&#8203;13261](https://github.com/pnpm/pnpm/issues/13261), [#&#8203;11523](https://github.com/pnpm/pnpm/issues/11523). - `pnpm audit` now excludes ignored advisories from vulnerability totals and severity counts, and reports them separately [#&#8203;14535](https://github.com/pnpm/pnpm/issues/14535). - `pnpm deploy` no longer requires `injectWorkspacePackages`. If a workspace dependency's peer has multiple possible versions, deployment reports `ERR_PNPM_DEPLOY_AMBIGUOUS_PEER` with the conflicting versions. Pin the peer with `overrides` to deploy without injection [#&#8203;9386](https://github.com/pnpm/pnpm/issues/9386). - Fixed concurrent installs sharing a store occasionally failing with an `ENOENT` error while importing a package file [#&#8203;14353](https://github.com/pnpm/pnpm/issues/14353). - Fixed installation failures when a linked local dependency provides a peer dependency also provided by an ancestor, including with `pnpm deploy --legacy`. - `pnpm install --node-linker=hoisted` no longer downloads skipped optional dependencies when `node_modules` already exists [#&#8203;14139](https://github.com/pnpm/pnpm/issues/14139). - Fixed `pnpm install` rejecting a symlinked lockfile when config dependencies are unchanged. Updates to config dependencies also preserve lockfiles with a byte order mark. Writes through symlinked lockfiles remain blocked [#&#8203;14372](https://github.com/pnpm/pnpm/issues/14372). - `pnpm install` now relinks workspace packages when `publishConfig.linkDirectory` changes. Frozen installs require the lockfile to be regenerated [#&#8203;14488](https://github.com/pnpm/pnpm/issues/14488). - Auto-installed optional peers now satisfy their declared range even when the workspace root uses a version outside that range [#&#8203;13867](https://github.com/pnpm/pnpm/issues/13867). - Fixed global virtual store paths for dependency cycles to consistently account for the runtime engine when dependencies have allowed builds [#&#8203;14341](https://github.com/pnpm/pnpm/issues/14341). - Standalone installations now preserve the bundled `node-gyp` files needed to build native dependencies. - Downloaded runtimes are now available to dependency lifecycle scripts during installation. - Node.js downloads from `nodeDownloadMirrors` now use URL-scoped npm credentials, including bearer tokens, basic auth, and `tokenHelper` [#&#8203;14334](https://github.com/pnpm/pnpm/issues/14334). - Fixed `globalDir` and `globalBinDir` handling in global configuration and environment variables, including `~/` expansion. This fixes `pnpm add -g` failing after `pnpm config set -g global-bin-dir` [#&#8203;14336](https://github.com/pnpm/pnpm/issues/14336). - The JavaScript pnpm can again switch to the project's pinned pnpm version on hosts without a matching native binary. If the requested version requires an unavailable native binary, the error now identifies the unsupported host [#&#8203;13622](https://github.com/pnpm/pnpm/issues/13622). - Global `pnpm config` commands now skip project package manager version switching, allowing authentication to be configured before downloading the pinned version [#&#8203;14463](https://github.com/pnpm/pnpm/issues/14463). - `pnpm self-update`, `pnpm with`, and automatic version switching no longer wait through registry retries when a configured registry has no signatures and `registry.npmjs.org` is unavailable [#&#8203;14483](https://github.com/pnpm/pnpm/issues/14483). - Fixed argument forwarding on Windows with `shellEmulator` enabled. Trailing backslashes, line breaks, and literal shell expressions are preserved [#&#8203;14548](https://github.com/pnpm/pnpm/issues/14548). - Relative `scriptShell` paths now resolve from the workspace root. Bare command names such as `bash` still use `PATH` [#&#8203;14422](https://github.com/pnpm/pnpm/issues/14422). - `pnpm import` now preserves the project-local lockfile when `lockfileDir` points elsewhere and restores the destination lockfile on failure. Branch lockfile imports leave the shared lockfile unchanged [#&#8203;14563](https://github.com/pnpm/pnpm/issues/14563). - `catalogMode` and `--save-catalog` no longer move local paths, tarballs, or `workspace:<path>` specifiers into catalogs [#&#8203;14437](https://github.com/pnpm/pnpm/issues/14437). - `--side-effects-cache`, `--no-side-effects-cache`, and `PNPM_CONFIG_SIDE_EFFECTS_CACHE` now toggle only the local cache, preserving any remote cache configured in `sideEffectsCache`. - `pnpm unpublish` now handles registry two-factor authentication challenges through web authentication or a one-time password prompt [#&#8203;14464](https://github.com/pnpm/pnpm/issues/14464). - `pnpm outdated` and `pnpm update` now follow GitHub Actions references using self-repository syntax, such as `uses: $/.github/actions/setup`. - `pnpm remove` now accepts `--unsafe-perm`. <!-- 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 --> ### [`v11.25.0`](https://github.com/pnpm/pnpm/releases/tag/v11.25.0): pnpm 11.25 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.24.0...v11.25.0) #### Minor Changes - Added an opt-in proof of concept that lets installs reuse a dependency's build output across machines, by publishing and restoring signed, organization-scoped artifacts through pnpr instead of running the lifecycle scripts locally. Configure it with the new `remoteSideEffectsCache` setting. A workspace names the eligible `organization` and `packages`; everything describing the act of signing — `publish`, `keyId`, `builderId`, `trustedKeys`, `privateKey` and the provenance fields — is refused in `pnpm-workspace.yaml` and read from the global config file or the environment instead. - Added macOS and Windows x64 and arm64 support to remote shared build artifacts [pnpm/pnpm#13771](https://github.com/pnpm/pnpm/issues/13771). - Added the `audit.ignorePrune` setting. When set to `true`, `pnpm audit --fix` removes ignored GHSA entries that no longer appear in the audit report. - Generalized the experimental shared-artifact protocol so candidates and signed payloads identify a discriminated subject. Dependency side effects use package and source-integrity subjects, while workspace tasks use project and task subjects. This changes shared-artifact request bodies and signed payloads. A pnpr server and its clients have to be on matching versions. - `pnpm init` now pins the latest pnpm version, instead of the version of pnpm that ran the command. A project scaffolded by an outdated pnpm therefore no longer inherits that staleness through its own `devEngines.packageManager` / `packageManager` pin [#&#8203;7490](https://github.com/pnpm/pnpm/issues/7490). The version is read from the `latest` tag on the package-manager registries. When that lookup cannot answer — no network, an unreachable or slow registry, `offline`, or a `latest` that the `minimumReleaseAge` / `trustPolicy` settings reject — `pnpm init` pins the running version as before, and never fails or hangs on the lookup. A `latest` that is older than the running pnpm is never pinned either. - A `scope` set in a project's `pnpm-workspace.yaml` is now ignored, with a warning naming where to set it instead. `pnpm login` records the scope as a `@scope:registry` route in the machine-global `auth.ini`, which outranks `~/.npmrc` in every project — so a repository-committed file could redirect a scope such as `@acme` for all of a user's other projects after one routine login. Use `--scope`, the `PNPM_CONFIG_SCOPE` environment variable, or the global config file instead [#&#8203;13557](https://github.com/pnpm/pnpm/issues/13557). - Verified remote build artifacts are persisted in the shared store with their signed origin metadata. Later installs reverify the artifact against current trust, policy, platform, and source before reuse, while invalid remote variants are quarantined per channel ([pnpm/pnpm#13771](https://github.com/pnpm/pnpm/issues/13771)). - Persist completed recursive tasks so `--resume-from` skips exactly the work that passed during a matching interrupted or failed `pnpm -r run` / `pnpm -r exec` invocation. When no compatible state exists, pnpm retains its graph-based resume behavior. - Allowed `pnpm update --patches` to refresh registry revisions through a configured pnpr server while retaining locked package versions. - Added explicit registry revision selection with `<version>+rN` and `pnpm update --patches` for refreshing revision artifacts without changing package versions. Registry-backed lockfile policy checks recognize historical revisions, and pnpr now preserves safe revision histories from upstream registries. - Workspace install, rebuild, pack, publish, stage, and lifecycle work now starts as soon as its dependencies finish instead of waiting for an unrelated topological group. - `pnpm stage approve` now approves several staged packages at once. Run it without a stage id to pick from the staged versions interactively, or pass a list of stage ids. The whole batch is approved with a single one-time password, and pnpm asks for a new one only once the registry stops accepting it. Inside a workspace, the selected packages are approved in dependency order, and a package whose workspace dependency could not be approved is skipped instead of being published against a dependency that never reached the registry. - Added per-task concurrency limits to workspace task orchestration. Set `tasks.<name>.concurrency` in `pnpm-workspace.yaml` to limit how many instances of that task may run across workspace projects at once: ```yaml tasks: build: concurrency: 2 ``` - Added support for registry replacement tarballs using standard integrity values, explicit revision fields, registry routing from the `registries` setting, non-redirecting integrity-addressed URLs, canonical safe-integer revision numbers, and pnpr proxying for immutable upstream revision artifacts. - `sideEffectsCache` now declares the whole of how a package's build output is reused — whether one is restored, whether one is saved, and the remote tier that shares it between machines: ```yaml sideEffectsCache: read: true write: true remote: org: acme packages: ['native-addon'] ``` `sideEffectsCache: true`, `sideEffectsCacheReadonly`, `remoteSideEffectsCache`, and its `organization` field all keep working. Where a field is set under both spellings the one above wins; where it is set under only one, it is kept. Two behaviors change, both bringing this CLI in line with what the Rust one already did: `sideEffectsCacheReadonly: true` now blocks writing to the cache, and setting it alongside `sideEffectsCache: false` gives a read-only view rather than switching the cache off entirely. A cache can also be declared write-only now, to populate one the run does not read. - Workspace task orchestration ([pnpm/rfcs#23](https://github.com/pnpm/rfcs/pull/23)). `pnpm -r run` and `pnpm -r exec` now schedule per task instead of in topological chunks: a task starts as soon as the tasks it depends on have finished, so a project no longer waits for unrelated projects that happen to share its chunk. A new `tasks` section in `pnpm-workspace.yaml` declares what a task depends on, using the `^` convention: ```yaml tasks: build: dependsOn: ['^build'] test: dependsOn: ['build'] lint: {} ``` `^name` means the named task in each of the project's workspace dependencies; a bare `name` means the task in the same project; an entry with no `dependsOn` declares an empty dependency list. A task with no entry behaves as `dependsOn: ['^<its own name>']`, which is exactly what the previous chunked ordering implied — an unconfigured workspace gets the scheduler improvement and nothing else changes meaning. A project without the script is reported skipped and passes its edges through to its own dependencies, so a scriptless package does not sever a chain. Also part of this change: - A dependency cycle among the tasks of a run is now an error naming the participating tasks (`ERR_PNPM_TASK_CYCLE`) instead of silently running in an arbitrary order. Setting `ignoreWorkspaceCycles: true` downgrades the error to a warning: the cycle's tasks run in an arbitrary order relative to each other. - `--resume-from` now skips exactly the transitive dependencies of the anchor package; work unrelated to the anchor still runs. - Under `--no-bail`, tasks whose dependencies failed are reported as skipped, not failed, and do not add to the exit code. - With `--bail` (the default), the first failure still ends the run at once and nothing new is dispatched — including scripts already queued behind the concurrency limit. - `pnpm -r run --dry-run <script>` prints the task graph that would execute without running anything (including skipping the `verifyDepsBeforeRun` check); `--json` emits the tasks and their resolved dependency edges. - Output is inherited rather than piped only when at most one script can ever be in flight (`--workspace-concurrency=1`, or the graph forces the scripts to run one after another). #### Patch Changes - An `_auth` entry in the global config file no longer decides which registry packages come from when something else says. A `registry` or `registries` declared in `pnpm-workspace.yaml` or the global config now wins over the route inferred from a stored credential, which still applies where nothing else declares one. The `pnpm_config__auth` environment variable is unchanged: it stays the way to point a CI runner at a mandated proxy, and still overrides what a repository declares. - Prevent installs through a symlinked `node_modules` directory from rewriting the target checkout [pnpm/pnpm#14286](https://github.com/pnpm/pnpm/issues/14286). - Treat empty scripts selected by a regular expression as missing before running dependent tasks. - The options type of the `fetch` command now declares `allowBuilds`, a setting its handler already forwarded to the installer. Type-level only — what `pnpm fetch` does is unchanged. - Filter hidden scripts matched by a regular expression during recursive runs when a visible script also matches. - Fixed automatically switched pnpm versions forcing all descendant pnpm processes to use the same version [pnpm/pnpm#14309](https://github.com/pnpm/pnpm/issues/14309). - Fixed `ERR_PNPM_UNUSED_PATCH` validation during incremental installs [pnpm/pnpm#13692](https://github.com/pnpm/pnpm/issues/13692). - Fixed `pnpm deploy --prod` failing when an excluded dev dependency was also declared as an optional peer dependency [pnpm/pnpm#14302](https://github.com/pnpm/pnpm/issues/14302). - `pnpm update -g` no longer downgrades a global package. `--latest` resolves the `latest` dist-tag, which can point at an older release than the one installed — after `pnpm add -g <pkg>@next`, for instance [#&#8203;14270](https://github.com/pnpm/pnpm/issues/14270). `pnpm update -g` also no longer changes the pnpm version. pnpm's own global install belongs to `pnpm self-update` [#&#8203;14270](https://github.com/pnpm/pnpm/issues/14270). - Copying a built package to its other hoisted locations no longer replaces the destination directory. With `nodeLinker: hoisted`, that replacement deleted the dependencies nested inside the destination's `node_modules`, and made concurrent copies of the same build chunk fail with `ERR_PNPM_ENOENT: no such file or directory, rename '.../node_modules/_tmp_...'` [#&#8203;12880](https://github.com/pnpm/pnpm/issues/12880). - `pnpm update` no longer replaces the specifier a project declares for a dependency that is also listed in `overrides`. A `catalog:` reference stays a `catalog:` reference, and a declared range stays as written, instead of being rewritten to the version the override resolved to [#&#8203;12115](https://github.com/pnpm/pnpm/issues/12115). - `pnpm update` no longer moves the range a project declares for a dependency that `overrides` also lists, even when the override repeats that range verbatim. Previously the updated `package.json` disagreed with the lockfile, so the next `pnpm install --frozen-lockfile` failed with a specifier mismatch [#&#8203;14224](https://github.com/pnpm/pnpm/issues/14224). - Make `pnpm add --lockfile-only` skip dependency linking [pnpm/pnpm#14286](https://github.com/pnpm/pnpm/issues/14286). - `--production` is accepted again as an alias of `--prod` on `install`, `fetch`, `prune`, `update`, `list`, `why`, and `sbom`, and the install that `verifyDepsBeforeRun` reproduces is now spelled with `--prod`. `pnpm run` no longer aborts with "unexpected argument '--production' found" after a production-only install [#&#8203;14147](https://github.com/pnpm/pnpm/issues/14147). - The progress output no longer overwrites the lines above it once it grows taller than the terminal window [#&#8203;14270](https://github.com/pnpm/pnpm/issues/14270). - Restoring a dependency's build from the remote side-effects cache no longer downloads files the store already holds. - Forward `patchedDependencies` hashes and `packageExtensions` to pnpr so server-side resolution preserves patches and package extensions in the lockfile and installed packages. - Published the workspace task graph and scheduler as `@pnpm/workspace.task-scheduler` so other workspace commands can use the same dependency-aware scheduling as recursive run and exec. - The environment variables for the remote side-effects cache are named for the setting they configure: `PNPM_SIDE_EFFECTS_CACHE_REMOTE_KEY_ID`, `..._BUILDER_ID`, `..._IMAGE_DIGEST`, `..._ARCHITECTURE_BASELINE`, `..._PRIVATE_KEY`, `..._BUILD_ENV`, `..._TRUSTED_KEYS` and `..._PUBLISH`. The `PNPM_REMOTE_SIDE_EFFECTS_CACHE_*` names keep working, and the new one wins when both are set. - A `devEngines.packageManager` range pin on pnpm is now recorded in `pnpm-lock.yaml`'s `packageManagerDependencies` when the running pnpm already satisfies it, using the running version and keeping the range as the recorded specifier. Previously only an exact pin — or a range resolved on the way through a version switch — reached the lockfile, so a range pin written by hand (or by any tool other than `pnpm add` / `pnpm self-update`) left the project without the shared resolution the pin exists to provide. - Fixed recursive `run` cleanup on Windows when a lifecycle script fails while another script's process tree is still running. - The update notification now suggests `pnpm self-update` when `PNPM_HOME` manages the pnpm in use, and the [standalone install script](https://pnpm.io/installation) otherwise — under Corepack, or when another package manager installed pnpm. `pnpm self-update` under Corepack names the standalone install script too. - Enforce `allowBuilds` when a prepared git dependency is reused from the shared store, and use the lockfile's canonical git resolution ID in approval suggestions. - Topologically sorting workspace projects now runs in linear time, fixing installs and lockfile updates that stalled for seconds on workspaces with thousands of projects forming deep dependency chains [#&#8203;14149](https://github.com/pnpm/pnpm/issues/14149), [#&#8203;14151](https://github.com/pnpm/pnpm/issues/14151). <!-- 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"> <picture> <source media="(prefers-color-scheme: light)" srcset="https://pnpm.io/img/users/notion.svg" /> <source media="(prefers-color-scheme: dark)" srcset="https://pnpm.io/img/users/notion_light.svg" /> <img src="https://pnpm.io/img/users/notion.svg" width="80" alt="Notion" /> </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> <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 --> ### [`v11.24.0`](https://github.com/pnpm/pnpm/releases/tag/v11.24.0): pnpm 11.24 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.23.0...v11.24.0) ##### Minor Changes - Added global build approvals [pnpm/pnpm#14101](https://github.com/pnpm/pnpm/issues/14101). ##### Patch Changes - Fixed pnpm v11 incorrectly reporting `confirmModulesPurge` as unrecognized when set in `pnpm-workspace.yaml`. The Rust CLI now identifies the unsupported option as a pnpm v11 setting instead of suggesting an unrelated setting. - `pnpm install --frozen-lockfile` no longer fails with `ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE` when the pinned pnpm version recorded in `pnpm-lock.yaml` has to be re-resolved before it can be installed. It runs the pnpm version the lockfile pins and leaves the lockfile unchanged [#&#8203;14124](https://github.com/pnpm/pnpm/issues/14124). - Under `nodeLinker: hoisted`, peer-resolution variants of an injected directory dependency (a `file:` snapshot) are materialized as separate copies again instead of collapsing onto the first-seen variant. Each copy keeps its own peer-resolved dependency set, so a project pinning one peer version no longer resolves another project's variant — Bit root components with conflicting peers across injected copies rely on this. - Fixed `pnpm install --merge-git-branch-lockfiles --frozen-lockfile` failing with `ERR_PNPM_OUTDATED_LOCKFILE` when a branch lockfile predates the removal of a dependency, or its move to another dependency group [#&#8203;13966](https://github.com/pnpm/pnpm/issues/13966). A dependency that no project declares anymore is no longer reinstated by the merge, and the packages it was the only path to are dropped with it. - Batch workspace publishing accepts a shared scope-specific credential, rejects mismatched credentials for a registry before publishing, and runs the `publish` and `postpublish` scripts after each completed registry group [pnpm/pnpm#14101](https://github.com/pnpm/pnpm/issues/14101). - The Rust CLI now honors five settings it recognized but ignored: `updateNotifier`, `legacyDirFiltering`, `initAuthorName` / `initAuthorEmail` / `initAuthorUrl`, `initLicense`, and `initVersion`. `pnpm install` and `pnpm add` check once a day for a newer pnpm and print how to get it (turn it off with `updateNotifier: false`); a `{<dir>}` filter selector can go back to matching the subtree below the directory with `legacyDirFiltering: true`; and `pnpm init` writes the configured author, license, and version into the `package.json` it scaffolds. `PNPM_CONFIG_INIT_VERSION` is now read as well. `maxsockets`, npm's spelling of `maxSockets`, is no longer ignored: both spellings are read from `pnpm-workspace.yaml`, the global config file, the environment, and the command line, in that increasing order of precedence — a value passed on the command line now wins even when the two sides spelled the setting differently. A `lastUpdateCheck` timestamp dated in the future — after a clock change, a restored snapshot, or a hand-edited state file — no longer silences the update check until that time comes around. `legacyDirFiltering` no longer reaches the workspace-root selectors pnpm generates for itself: the `!{<workspace-root>}` exclusion a recursive `run` / `exec` / `add` / `test` appends, and the `{<workspace-root>}` inclusion `--workspace-root` appends. Read as subtree matches they named every project below the root, so a recursive command under the setting selected nothing at all, and `--workspace-root` pulled in every project below the root instead of the root alone [#&#8203;14101](https://github.com/pnpm/pnpm/issues/14101). - `pnpm install --frozen-lockfile` no longer fails when `pnpm-lock.yaml` records the pinned pnpm version alongside an engine package the running pnpm does not install it from. An entry pinning another version is still refused, and a plain install rewrites the block [#&#8203;14124](https://github.com/pnpm/pnpm/issues/14124). ### [`v11.23.0`](https://github.com/pnpm/pnpm/releases/tag/v11.23.0): pnpm 11.23 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.22.0...v11.23.0) #### Minor Changes - `pnpm config get` and `pnpm config list` now show the settings pnpm acts on under their documented names: - `registries` shows the registries pnpm resolves from, merged across every source (`.npmrc`, `pnpm-workspace.yaml`, the global config, CLI flags), in the shape the setting is written in: keyed by registry URL, with the default registry declared as the bare `@` scope. Built-in routes are included — the `@jsr` scope and the `npmjs` and `gh` prefixes — unless pointed elsewhere. Previously `pnpm config get registries` printed `undefined`. - `update` and `audit` show the effective sections, whichever spelling set them. The deprecated internal spellings (`updateConfig`, `auditConfig`, `auditLevel`) are no longer listed. - `catalogs` shows the complete resolved catalog set — the singular `catalog` block is its `default` entry — whichever spelling declared it. - The `registry` and `@scope:registry` entries show the merged routes rather than raw `.npmrc` values, so they always agree with the `registries` view. - Settings that no supported pnpm version recognizes get their own warning. A key in the global config file that this version of pnpm does not read is no longer reported with advice to move it to a project-level `pnpm-workspace.yaml` (where it would be ignored too); the warning now says the setting is not recognized by this version of pnpm, names the pnpm version that does read it when there is one (for example, `globalShims` is a pnpm v12 setting), and suggests the closest real setting name when the key looks like a typo. Unrecognized and non-camelCase keys in a project's `pnpm-workspace.yaml`, previously ignored silently, are now reported the same way. `pnpm config get <key>` and `pnpm get <key>` no longer print config-load warnings, so a script capturing the value gets the value alone. - The `importPackage` pnpmfile hook is deprecated. pnpm now prints a warning when a pnpmfile defines it, and the hook will be removed in the next major version. It also opts the installation out of the parallel package importer, making installation slower. If you rely on this hook, comment on [#&#8203;14101](https://github.com/pnpm/pnpm/issues/14101). - `node_modules/.modules.yaml` no longer records the registries an install resolved from, and the recorded copy is dropped from the file on the first install that rewrites it. It dated from the lockfile format that spelled a dependency's path relative to its registry, where reading an installed tree meant knowing the registries it was installed with. Dependency paths have not carried a registry for several major versions, and the recorded copy outlived its use: `pnpm list`, `pnpm why`, and single-project installs preferred it over the project's own configuration, so a project whose registry had changed since its last install was still read through the old one. They now use the configured registries, like every other command already did. - When `enableGlobalVirtualStore` is on, every process pnpm spawns for the project (`pnpm run`, `pnpm exec`, lifecycle scripts) now receives a `NODE_PATH` pointing at the project's hoisted `node_modules`, plus a `NODE_OPTIONS` `--import` flag that registers a resolve hook restoring `NODE_PATH` lookups for ESM imports. Dependencies that import undeclared ("phantom") packages keep resolving under the global virtual store — for both CommonJS and ESM — without installing the `@pnpm/plugin-esm-node-path` config dependency [pnpm/pnpm#9618](https://github.com/pnpm/pnpm/issues/9618). Tools run by `pnpm dlx` resolve such dependencies too: the JS CLI passes them the same environment, while the Rust CLI's dlx cache is self-contained, so its layout already exposes them. - A registry can now declare that its abbreviated metadata carries the `time` field, so `resolutionMode: time-based` reads the full metadata document only from the registries that need it: ```yaml resolutionMode: time-based registries: https://npm.internal.example/: supportsTimeField: true ``` `registry.npmjs.org` omits `time` from abbreviated metadata, so a time-based resolution has to fall back to the much larger full document. That fallback used to be all-or-nothing: `registrySupportsTimeField` answered for every registry at once, so a project resolving from both the public registry and a Verdaccio instance either paid for full metadata everywhere or claimed a `time` field npmjs does not serve. The answer is now per registry, and `registrySupportsTimeField` remains the answer for every registry that does not declare one. The declaration is also sent to a pnpr server, which applies it to the resolution it runs on the client's behalf. - A pnpr resolve request now carries the client's registries the way the `registries` setting declares them — keyed by URL, with the scopes routed to each, the bare-specifier prefix each answers to, and each one's `serverType` — in place of the prefix map it used to send. The server routes them through the same inversion the config reader runs, so a pnpr-served install resolves a scoped dependency from the registry that scope is routed to, which it previously could not: only the default registry and the prefix-addressed ones reached the server. A declared `serverType` reaches it too, so the tarball URLs pnpr omits from the lockfile match the ones the client reconstructs. Built-in scope routes the project has not pointed elsewhere are not declared, so a pnpr server's allowlist is not asked about `npm.jsr.io` on requests that resolve no JSR package. A registry a request only declares is no longer refused up front for being off the server's allowlist — a client describes its whole configuration, including scopes a given resolve never reaches, so a stray `@scope:registry` in a developer's `~/.npmrc` no longer fails every install against a pnpr server that does not serve it. The boundary moves to the fetch itself: an origin the resolve does reach is refused before the request leaves the server, with the same message. This changes the resolve and verify-lockfile request bodies. A pnpr server and its clients have to be on matching versions; the protocol is still experimental and unversioned. - The `registries` setting now declares a registry once, keyed by its URL, with everything about that registry in the entry: how it lays out tarball URLs, the scopes routed to it, and the bare-specifier prefix it answers to. ```yaml registries: https://artifactory.example.com/artifactory/api/npm/npm-virtual/: serverType: artifactory scopes: ['@acme', '@acme-internal'] prefix: work ``` - **`serverType`** tells pnpm how the registry lays out its tarball URLs, which decides whether a URL can be omitted from `pnpm-lock.yaml`: - **undeclared** (the default) — strict. Only the exact canonical URL is treated as reconstructible. - **`npm`** — the registry behaves like `registry.npmjs.org`, which also serves a scoped package from its percent-encoded path. Declare this for a faithful mirror or caching proxy of the public registry so its tarball URLs can be omitted too. - **`artifactory`** — JFrog Artifactory repeats the scope in a scoped package's tarball filename (`@acme/widget/-/@acme/widget-1.0.0.tgz`) where the npm registry strips it (`@acme/widget/-/widget-1.0.0.tgz`). Declaring it lets pnpm rebuild that URL, so it is omitted from `pnpm-lock.yaml` instead of being written out for every scoped package [pnpm/get-npm-tarball-url#16](https://github.com/pnpm/get-npm-tarball-url/issues/16). - **`scopes`** lists the `@`-prefixed scopes that resolve from this registry. A bare `'@'` is the scope-less default registry, the one the `registry` setting names. - **`prefix`** is the alias a dependency addresses this registry by, as in `"foo": "work:^1.0.0"`. The layout is never inferred from the registry URL, so nothing changes unless you declare it; `registry.npmjs.org` continues to behave as `npm` without being declared. Because the lockfile depends on `serverType`, it is read from `pnpm-workspace.yaml` only — a `serverType` in the global `config.yaml` is ignored, so one developer's machine cannot shape a lockfile their collaborators read back with a different layout. Credentials are rejected in this setting, in a key as well as in a field, and still belong in `.npmrc`. An entry that routes nothing to itself and matches no configured registry is reported as a warning rather than silently ignored. ##### Migrating The older `registries` shape, a map of `<scope>: <url>` strings, still works and needs no change: ```yaml registries: '@acme': https://npm.acme.example/ ``` `namedRegistries` is deprecated in favor of the `prefix` field, and is still read for prefixes `registries` does not declare. `toLockfileResolution` and `isCanonicalRegistryTarballUrl` now take their registry and layout as an options object rather than positional arguments, so `@pnpm/lockfile.utils` and `@pnpm/resolving.tarball-url` get a major bump. - An install that had to re-hash store files to verify them now reports it. If that cost more than a second, it says how long — `The integrity of N files was checked in 2.5s.` — and if it was quick but covered more than a thousand files, it names the cause instead: their timestamps changed since the store recorded them, which a backup tool, an antivirus scan or a copied store can do. - Added `virtualStoreType`, which names where the virtual store lives — one store per machine, or one per project: ```yaml virtualStoreType: global # or: project ``` It is the canonical spelling of `enableGlobalVirtualStore`, which keeps working. When a project sets both, `virtualStoreType` wins. It can also be set through `PNPM_CONFIG_VIRTUAL_STORE_TYPE` and read back with `pnpm config get virtualStoreType`. The default is unchanged — `project`, so the shared store stays opt-in. The setting is independent of `nodeLinker`. `isolated` and `pnp` both work with either store type, and `hoisted` writes no virtual store at all, so it is unaffected. #### Patch Changes - `pnpm add --allow-build` now adds to the `allowBuilds` entries already in `pnpm-workspace.yaml` instead of replacing them [#&#8203;13872](https://github.com/pnpm/pnpm/issues/13872). - Kept pending build approvals available after removing an unrelated dependency. - `pnpm approve-builds` now removes `onlyBuiltDependencies`, `onlyBuiltDependenciesFile`, `neverBuiltDependencies`, and `ignoredBuiltDependencies` from `pnpm-workspace.yaml` when it writes `allowBuilds`. Those settings were replaced by `allowBuilds` in pnpm 11 and silently ignored since, so a workspace migrated from pnpm 10 kept them around looking active. - `pnpm audit` no longer reports a patched version that was never published or is deprecated. The inferred patched range (e.g. `>=4.17.24` from `<=4.17.23`) is now checked against the registry packument, and the report is corrected to the lowest non-deprecated published version that satisfies it (e.g. `>=4.18.1` when `4.17.24` does not exist and `4.18.0` is deprecated). When no published version satisfies the range, the report shows `Patched versions: None`. This also prevents `pnpm audit --fix` from adding overrides or `minimumReleaseAgeExclude` entries for patches that do not exist [#&#8203;13824](https://github.com/pnpm/pnpm/issues/13824). `pnpm audit --fix` and `pnpm audit --fix update` no longer add a `minimumReleaseAgeExclude` entry when the registry packument shows that the minimum patched version was never published. Previously such entries were written for versions that do not exist, which would have let a later publish of that version bypass the `minimumReleaseAge` gate [#&#8203;11563](https://github.com/pnpm/pnpm/issues/11563). The `--json` output of `pnpm audit` now returns `patched_versions: null` for advisories whose inferred patch is not available (never published, skipped, yanked, or deprecated), making it easier for tooling to distinguish "no fix available" from "fix available at version X". - Fixed `pnpm patch-commit` in project and edit paths containing non-ASCII characters. - The package and bump pickers of `pnpm change` now size their page from the terminal height instead of always showing 7 rows. They fall back to 7 rows when the terminal height is unknown [`pnpm/pnpm#13815`](https://github.com/pnpm/pnpm/issues/13815). - Canceling a `pnpm change` prompt with Ctrl-c no longer prints a stack trace. It reports `Change canceled` and exits with a success status, like the other interactive commands [#&#8203;13814](https://github.com/pnpm/pnpm/issues/13814). - Re-fetch full registry metadata when `minimumReleaseAge` is enabled and an abbreviated packument's `time` map omits timestamps for some versions. This prevents mature versions from being filtered out and resolution from falling back to the lowest matching version [pnpm/pnpm#13741](https://github.com/pnpm/pnpm/issues/13741). - A config dependency carrying an inline integrity (the `<version>+<integrity>` form, or the object form without a `tarball`) now takes its tarball URL from the registry's packument instead of deriving it from the registry URL, so migrating one costs an extra metadata request. On a registry that serves tarballs from a path pnpm cannot derive, GitLab's group endpoint for one, installing such a config dependency failed with a 404 while the same package installed fine as a regular dependency [#&#8203;13765](https://github.com/pnpm/pnpm/issues/13765). - Fixed `PNPM_CONFIG_NODE_VERSION` being ignored when setting the Node.js version used for compatibility checks. - A custom fetcher can no longer replace the archive integrity that `pnpm-lock.yaml` pins: the locked value is restored after a `canFetch` or `fetch` hook rewrites the resolution, and delegating a locked archive to a directory or git source now fails instead of installing unverified content. The Rust CLI now also loads the pnpmfiles named by the `pnpmfile` setting (a single path or an ordered list), and hands custom fetchers native `localTarball` and `remoteTarball` callbacks — including on a fresh install that has to compute a missing tarball integrity, which is then reused by later offline installs. File maps a fetcher returns are accepted only when they match what those native callbacks extracted. - Fixed an issue where running `pnpm dedupe --check` in projects with `nodeLinker: hoisted` would cause dependencies to be moved out of `node_modules` into `node_modules/.ignored`. - `pnpm deploy --prod` and `pnpm deploy --no-optional` no longer list the excluded dependency groups in the deployed `package.json` and `pnpm-lock.yaml`. The deployed lockfile referenced packages that the deploy left out of its graph, so installing in the deploy directory afterwards created dangling symlinks [#&#8203;13623](https://github.com/pnpm/pnpm/issues/13623). - Don't treat files like `license16.json` as a package license when deciding if the workspace LICENSE file should be included in the packed package. - `pnpm exec --recursive --no-reporter-hide-prefix` no longer prints a blank prefixed line after each chunk of a command's output, and no longer splits a line in two when it straddles a chunk boundary. - Fixed `404` errors when installing from a registry that serves scoped packages only from a percent-encoded path, such as GitHub Enterprise Server. Outside `registry.npmjs.org`, a tarball URL that encodes the scope separator as `%2f` or `%2F` is no longer mistaken for one that pnpm can rebuild from the package name, version, and registry, so it is kept in `pnpm-lock.yaml` and requested verbatim on the next install [#&#8203;13534](https://github.com/pnpm/pnpm/issues/13534). - Fixed `trustPolicyExclude` and `minimumReleaseAgeExclude` being ignored when set to a single string instead of a list. The value was read one character at a time, so the exclusion never matched the package it named — and a `*` anywhere in it matched every package, silently switching the policy off. - `pnpm init` now pins the exact pnpm version instead of a `^` range, and records it in the `packageManager` field alongside `devEngines.packageManager`. Corepack reads only `packageManager` and accepts nothing but an exact version, so it rejected the generated `package.json` with "expected a semver version" [pnpm/pnpm#13969](https://github.com/pnpm/pnpm/issues/13969). A package created inside an existing workspace is still left unpinned — it follows the pin at the workspace root — and `--no-init-package-manager` still scaffolds a manifest without any pin. In pnpm 12, `pnpm init` also honors `initType` and its `--init-type` flag, so the manifest it writes is the same one pnpm 11 writes. - Fixed an issue where package overrides were written into the metadata cache, causing removed overrides to keep applying on subsequent installs [pnpm/pnpm#13918](https://github.com/pnpm/pnpm/issues/13918). - On Windows, upgrading pnpm no longer leaves a stale `pnpm.ps1` behind. PowerShell resolves `pnpm.ps1` ahead of `pnpm.cmd`, so a shim written by an older installation kept running the previous version. Linking the pnpm CLI's bins now deletes it [#&#8203;13919](https://github.com/pnpm/pnpm/issues/13919). - Fixed an inconsistency where `minimumReleaseAgeExclude` (and `trustPolicyExclude`) wildcard/bare-name rules behaved differently in the evaluator and normalizer. A bare rule now consistently evaluates as matching every version, preventing unexpected behavior and silent widening of version policy exemptions when pnpm rewrites the workspace manifest [pnpm/pnpm#13725](https://github.com/pnpm/pnpm/issues/13725). - A frozen install no longer rewrites the `packageManagerDependencies` block of `pnpm-lock.yaml`. When the pnpm version pinned by `devEngines.packageManager` (or by `packageManager`) is missing from the lockfile or no longer matches it, `--frozen-lockfile` now fails with `ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE` instead of resolving the version and saving it, so a manifest whose pin was bumped without regenerating the lockfile can no longer pass CI [#&#8203;14009](https://github.com/pnpm/pnpm/issues/14009). - A git dependency installed over HTTPS from a hosted repository now keeps its branch, tag, or version range in the specifier recorded in `package.json`. It was written back without one, so the next `pnpm update` moved the dependency to the repository's default branch [#&#8203;13999](https://github.com/pnpm/pnpm/issues/13999). - Fixed `pnpm update --global --latest` failing with a 404 error when a globally installed package was not added from the registry by name. Packages installed from a local path (`link:`/`file:`), a git repository, a tarball URL, an `npm:` alias, or a named registry now keep their spec during a global update instead of being looked up by name in the default registry. See [#&#8203;12854](https://github.com/pnpm/pnpm/issues/12854). - Fix recursive `pnpm update <name>@<version>` so an exact pinned update stays scoped to the requested version line: copies of the same package on another major line — or, for a `0.x` request, another minor line — keep their locked resolution instead of being re-resolved along with the target. - Under `nodeLinker: hoisted`, a dependency declared against a peer-resolution variant of a package version is no longer dropped from the installed layout. All variants of a version share one hoisted copy, and edges pointing at any of them now resolve to it, so the depending project keeps the package in its `.package-map.json` and the depending package keeps it in its `node_modules/.bin`. - Fixed `pnpm install --merge-git-branch-lockfiles` deleting the per-branch lockfiles when the `lockfile` setting is `false`. Such an install never reads them, so it has nothing to merge them into and now leaves them alone. - Fixed `pnpm install` sometimes not exiting after printing `Done in Xs` [#&#8203;12297](https://github.com/pnpm/pnpm/issues/12297). - Fixed pnpm failing to read `.modules.yaml` files containing long dependency paths [#&#8203;13875](https://github.com/pnpm/pnpm/issues/13875). The manifest is now parsed as JSON (the format pnpm writes it in), falling back to the YAML parser only for manifests written by old pnpm versions. - With `preferSymlinkedExecutables`, `NODE_PATH` again points at the virtual store of the workspace root when pnpm is run from inside a workspace package, so scripts can resolve dependencies that live only in the hoisted store [#&#8203;13912](https://github.com/pnpm/pnpm/issues/13912). - Reduced registry metadata requests during dependency resolution by reusing cached metadata when lockfile preferences prove that no uncached version can win [pnpm/pnpm#13976](https://github.com/pnpm/pnpm/issues/13976). - `pnpm pkg get` and `pnpm pkg set` now accept hyphens inside a dot-notation property path, so `pnpm pkg get dependencies.some-package-name` reads the key instead of failing with `ERR_PNPM_UNEXPECTED_TOKEN_IN_PROPERTY_PATH`. The bracketed and quoted forms already worked and are unchanged. - A resolve request now carries the client's `resolutionMode`, so an install delegated to a pnpr server picks versions the way the client would. `time-based` and `lowest-direct` reached the server as nothing at all, leaving it on its `highest` default: the returned lockfile pinned the highest satisfying version of every dependency, and the setting appeared to be ignored. This adds a field to the resolve request body. A server older than its client ignores it and keeps resolving `highest`; the protocol is still experimental and unversioned. - Fixed `pnpm` installs using pnpr to honor the client's `autoInstallPeers`, `dedupePeers`, and `excludeLinksFromLockfile` settings [pnpm/pnpm#13389](https://github.com/pnpm/pnpm/issues/13389). - `pnpm remove` now prunes undecided entries (`"set this to true or false"`) from `allowBuilds` in `pnpm-workspace.yaml` when `sharedWorkspaceLockfile: true` and the corresponding packages are removed [pnpm/pnpm#13892](https://github.com/pnpm/pnpm/issues/13892). - Fixed workspace discovery for `pnpm-workspace.yaml` files without a `packages` field so commands only consider the workspace root instead of recursively scanning nested projects [#&#8203;14047](https://github.com/pnpm/pnpm/issues/14047). - A runtime installed through `devEngines.runtime` now matches the host when `supportedArchitectures` lists several platforms. Listing `os: [darwin, linux]` and `cpu: [x64, arm64]` used to install the runtime built for the first entry of each list, so a machine running Linux on arm64 got a macOS x64 Node.js that could not execute [#&#8203;13898](https://github.com/pnpm/pnpm/issues/13898). - `pnpm sbom` now fails with `ERR_PNPM_SBOM_MISSING_IMPORTERS` when `pnpm-lock.yaml` has no entry for a selected project, instead of writing an SBOM that under-reports that project's dependencies. Previously this crashed with `Cannot read properties of undefined (reading 'devDependencies')`. - `pnpm self-update` now rewrites a simple `devEngines.packageManager.version` range (`^`/`~`) to the newly installed version, keeping the operator — matching how `pnpm update` and `pnpm runtime set` rewrite ranges. Complex ranges such as `>=8.0.0` that the new version satisfies are still left unchanged [#&#8203;13935](https://github.com/pnpm/pnpm/issues/13935). - `pnpm self-update <tag>` no longer downgrades when the dist-tag points at the pnpm version already running and that version is younger than `minimumReleaseAge`. The maturity cutoff moved the tag back to the previous mature release, so `pnpm self-update next-12` on v12.0.0-rc.4 switched to v12.0.0-rc.3. - `pnpm set-script` now updates `package.json` instead of failing with `ERR_PNPM_NOT_IMPLEMENTED` [`pnpm/pnpm#13956`](https://github.com/pnpm/pnpm/issues/13956). - `pnpm update` now preserves the existing range operator when updating a prerelease dependency. See [#&#8203;7002](https://github.com/pnpm/pnpm/issues/7002). - Installs are faster in workspaces that declare inter-workspace dependencies with plain ranges (`"*"`, `"^1.2.3"`) rather than the `workspace:` protocol. With `preferWorkspacePackages` enabled, linking such a dependency no longer makes a registry request that cannot change the outcome — and workspace packages that were never published no longer cost a 404 on every install. - Added `fetchWarnTimeoutMs` and `fetchMinSpeedKiBps` to the Rust pnpm CLI and its N-API bindings. Slow registry metadata requests and tarball downloads now emit pnpm-compatible warnings without exposing URL credentials, query parameters, fragments, or control characters [pnpm/pnpm#12042](https://github.com/pnpm/pnpm/issues/12042). - An override change is now absorbed by the fast lockfile update even when another, unchanged override uses the `catalog:` protocol. Previously any `catalog:`-valued override forced a full re-resolution whenever the override list changed, which could move unrelated packages in the lockfile (for example after `pnpm audit --fix` added an override). - Packed workspace package manifests now preserve dependency order, making repeated `pnpm pack` output deterministic [#&#8203;10167](https://github.com/pnpm/pnpm/issues/10167). - `pnpm update <name>@<version>` now fails with `ERR_PNPM_UPDATE_VERSION_ON_INDIRECT_DEP` when the package is not a direct dependency of any selected project, instead of quietly updating it to whatever a fresh install would resolve. There is nowhere to record the version in that case, so the request cannot be honored, and the error points at the `overrides` entry that does pin a transitive dependency. Ranges and tags are unaffected, and a package that any selected project declares directly still takes its version as before. - `trustPolicy: no-downgrade` no longer aborts the install with `ERR_PNPM_MISSING_TIME` on registries that serve no per-version `time` field when `minimumReleaseAgeIgnoreMissingTime` is set. The trust check reads the same publish dates the `minimumReleaseAge` check does, so it now honors the same opt-in and skips the affected package with a warning [#&#8203;12446](https://github.com/pnpm/pnpm/issues/12446). `minimumReleaseAgeIgnoreMissingTime` no longer lets a lockfile entry the registry does not list pass the `minimumReleaseAge` check during lockfile verification. The opt-in covers a registry that cannot date its releases; a packument that does date every version it lists is saying it never published this one, which stays a hard failure. The missing-`time` warning now names the check it is reporting on, so a package whose `minimumReleaseAge` and `trustPolicy` checks are both skipped warns about both instead of only the first. - `pnpm update <pkg>@<version>` now updates only the selected packages and leaves unrelated dependencies unchanged. A selector that renames the package it installs — `pnpm update <alias>@npm:<pkg>@<version>` or the `jsr:` equivalent — now targets the package the alias installs rather than the alias. - Fixed `verifyDepsBeforeRun` being ignored when set to `install`, `warn`, `error`, or `prompt` through the `PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN` environment variable or the `--config.verify-deps-before-run` flag [#&#8203;13816](https://github.com/pnpm/pnpm/issues/13816). Only the boolean values were accepted before, so a string value was silently dropped. - `pnpm version <bump>` with `--dry-run` no longer edits `package.json` files. It now only reports the bumps it would make, and skips the working tree check, the version lifecycle scripts, the commit, and the tag [`pnpm/pnpm#13953`](https://github.com/pnpm/pnpm/issues/13953). <!-- 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.22.0`](https://github.com/pnpm/pnpm/releases/tag/v11.22.0): pnpm 11.22 [Compare Source](https://github.com/pnpm/pnpm/compare/v11.21.0...v11.22.0) #### Minor Changes - Added `pnpm cache path`, which prints the directory pnpm uses for its metadata cache. CI setups can use it to cache that directory — including the lockfile verification log, which lets a job skip re-checking an unchanged lockfile against the configured supply-chain policies. - `--config.config-dir` no longer reaches the config through a project's `pnpm-workspace.yaml`, and neither do the `--config.` spellings of the other settings a project manifest may no longer contribute (`--config.pnpm-home-dir`, `--config.workspace-dir`, `--config.global-pkg-dir`, `--config.root-project-manifest-dir`). None of them was ever a supported way to set those directories: pnpm resolves them from the environment, and these flags took effect only because the project-manifest merge re-applied the command line afterwards. The dedicated flags, such as `--dir` and `--global-dir`, are unaffected [#&#8203;13629](https://github.com/pnpm/pnpm/issues/13629). - `pnpm config set` refuses to write a setting to a project's `pnpm-workspace.yaml` that pnpm does not read from there, rather than leaving a key in the file that does nothing. Those settings are `configDir`, `pnpmHomeDir`, `stateDir` and the others that name machine-level state. The command fails with `ERR_PNPM_CONFIG_SET_NOT_A_PROJECT_SETTING`, naming where the setting does belong when it belongs somewhere. `pnpm config delete` still clears one that a file already carries, in whichever spelling it uses [#&#8203;13629](https://github.com/pnpm/pnpm/issues/13629). - Added a new setting `minimumReleaseAgeExcludePrune`. When enabled, `pnpm add`, `pnpm update`, and `pnpm remove` prune the entries of `minimumReleaseAgeExclude` in `pnpm-workspace.yaml` that the freshly written lockfile no longer resolves: versions that are gone are dropped (an entry is removed once none of its versions remain), and entries for packages that are no longer in the lockfile are removed too. Name patterns (`@scope/*`) are always kept. The cleanup is skipped when the install's lockfile does not cover the whole workspace (`sharedWorkspaceLockfile: false`), since entries another project still needs would look stale. Renamed `cleanupUnusedCatalogs` to `catalogPrune`, so that catalog pruning and release-age exclude pruning use one vocabulary. `cleanupUnusedCatalogs` continues to work; when both are set, `catalogPrune` wins. - A project's `pnpm-workspace.yaml` can no longer choose where pnpm keeps its credentials, its own installation, or the registry it downloads its next version from. One of those settings is `configDir`, which decided where `pnpm login` writes the granted token. `bin`, `dir`, `globalBinDir`, `globalDir`, `npmrcAuthFile`, `pnpmHomeDir`, `stateDir`, `userconfig` and `workspaceDir` are ignored there now too, and pnpm warns about the ones it finds. `cacheDir` and `storeDir` are unaffected [#&#8203;13629](https://github.com/pnpm/pnpm/issues/13629). - Resolving a Node.js runtime version (`devEngines.runtime` / `runtime:` specifiers) is now much faster: the per-version release metadata is cached in the pnpm cache directory after its signature is verified, and an exact stable version such as `runtime:22.23.2` no longer downloads the Node.js release index. A pinned runtime whose metadata was fetched once resolves without any network access, which removes the noticeable delay on the first `node` invocation in a project pinning an already-downloaded runtime [#&#8203;13899](https://github.com/pnpm/pnpm/issues/13899). #### Patch Changes - Fixed intermittent `ERR_PNPM_ENOENT` and `ERR_PNPM_ENOTEMPTY` errors while renaming `_tmp_*` directories during installation with `nodeLinker: hoisted`, in workspaces that also use `patchedDependencies`. - `pnpm add` no longer re-resolves the dependency graph when `pnpm-lock.yaml` already holds a version satisfying the request — promoting a transitive dependency to a direct one, or adding to a second workspace package what a first one already depends on, now only saves the dependency in `package.json` and records its importer entry. A satisfying locked version is necessary but not sufficient: the install still falls back to a full resolution for a dist tag, an alias, a `workspace:`/`catalog:`/git/tarball specifier, `--save-peer`, an overridden package, a `catalogMode` other than `manual`, and — under `resolutionMode: time-based` or `lowest-direct`, which resolve a direct dependency to the low end of its range — a range several locked versions satisfy. - Global installs now switch over atomically. The command shims in the global bin directory point at a stable per-package link rather than at the directory a particular install produced, so `pnpm add -g` and `pnpm update -g` activate a new version by moving that one link instead of rewriting every shim. A command can no longer be missing from `PATH` while an install is in progress, and a failed install leaves the previous version in place. - `pnpm audit --fix` and `pnpm audit --fix update` no longer add `minimumReleaseAgeExclude` entries for patched versions that were published before the `minimumReleaseAge` cutoff. The publish time of each minimum patched version is now checked against the registry metadata, and only versions young enough to be blocked by the age gate get an exclusion entry [#&#8203;11563](https://github.com/pnpm/pnpm/issues/11563). - `pnpm add <pkg>@<version>` and `pnpm update <pkg>@<version>` under a non-manual `catalogMode` now move the catalog entry's resolution to the requested version. Previously, when the catalog entry was a range that covered the requested version but resolved to a different one, the request was dropped silently: nothing was installed, nothing was written, and no error was raised. - A project that wasn't part of an install that moved a catalog entry now follows the entry the next time it is installed. It used to keep the version the entry resolved to before — a version the entry no longer allowed — and no later install corrected it, so one catalog entry ended up resolved to two versions. - `pnpm add <pkg>@<version>` and `pnpm update <pkg>@<version>` under `catalogMode: strict` no longer fail with `ERR_PNPM_CATALOG_VERSION_MISMATCH` when the catalog entry is a range that the wanted version satisfies. The dependency keeps using the catalog; only a version that really falls outside the catalog's range is rejected [#&#8203;13715](https://github.com/pnpm/pnpm/issues/13715). - A changed `catalogs` or `pnpm.overrides` block no longer has to be the only change for `pnpm install` to update the lockfile in place. Editing an override while also removing a dependency, or changing a catalog entry in the same commit as a range bump, is now absorbed in one pass instead of re-resolving the whole dependency graph [#&#8203;13799](https://github.com/pnpm/pnpm/issues/13799). Fixed the lockfile an in-place override update wrote when the overridden package was also a catalog entry: the entry kept the version it had before the override moved the package. The same could happen in reverse, when a catalog entry moved a package an override pins. Both cases now re-resolve instead. - `pnpm install` now updates the lockfile in place even when several kinds of changes happened since the last install — for example a removed dependency together with a widened `ignoredOptionalDependencies` list, or a dependency edit alongside a patch or settings change. Previously any combination of changes forced a full re-resolution [#&#8203;13763](https://github.com/pnpm/pnpm/issues/13763). - `pnpm deploy` injects workspace dependencies again, so the deploy directory is self-contained instead of symlinking back into the source workspace [#&#8203;13754](https://github.com/pnpm/pnpm/issues/13754). Enabling `injectWorkspacePackages` with `dedupeInjectedDeps` disabled now also rewrites already-linked workspace dependencies to injected copies. - `pnpm deploy --no-optional` no longer writes a lockfile whose snapshots reference optional dependencies that the deploy excluded. - Removing the last dependency that references a catalog entry via the fast lockfile update no longer leaves the stale catalog entry in `pnpm-lock.yaml`. - A git dependency whose clone (or shallow fetch) fails now reports which package it belongs to, under the `ERR_PNPM_GIT_FETCH_FAILED` code, with credentials in the repository URL redacted. When the lockfile records an SSH remote, the error also explains that fetching it needs an SSH key for that host, and that a lockfile entry written before pnpm v11.21 can be re-recorded over HTTPS with `pnpm update <package>` [#&#8203;13743](https://github.com/pnpm/pnpm/issues/13743). - An `integrity` recorded on a git dependency's resolution (`resolution: {type: git, repo, commit, integrity: sha512-…}`) is no longer treated as a checksum. pnpm never verifies a git checkout against such a hash — the commit pins the content — so it is now dropped when the lockfile is rewritten, and `pnpm sbom` no longer republishes it as a CycloneDX/SPDX checksum. Lockfiles carrying one also load again instead of failing with `ERR_PNPM_BROKEN_LOCKFILE` [#&#8203;13042](https://github.com/pnpm/pnpm/issues/13042). `pnpm sbom` now also publishes the checksum of a `type: binary` runtime archive, which pnpm does verify. - A git dependency whose `git ls-remote` fails now reports the `ERR_PNPM_GIT_RESOLVE_FAILED` code, naming the dependency instead of printing a bare `git` invocation, with credentials in the repository URL redacted. A specifier that does not ask for SSH resolves over HTTPS, because the URL recorded in the lockfile has to work on every machine that installs it, so the error explains how to substitute the transport on a machine that can only reach the host over SSH (`git config --global url."git@<host>:".insteadOf "https://<host>/"`) [#&#8203;13743](https://github.com/pnpm/pnpm/issues/13743). A missing `git` executable is reported as one, instead of surfacing the raw failure to start the process. Credentials embedded in a git specifier are redacted from the "Could not resolve \<ref> to a commit of \<repo>" errors too. Resolving a public repository makes one `git ls-remote` round-trip instead of two. - `pnpm install` after moving a dependency between `dependencies`, `devDependencies`, and `optionalDependencies` now updates the lockfile in place instead of re-resolving the whole dependency graph [#&#8203;13696](https://github.com/pnpm/pnpm/issues/13696). - `syncInjectedDepsAfterScripts` no longer fails with `ERR_PNPM_UNSUPPORTED_INODE_TYPE` when a workspace package contains an inode that is neither a file nor a directory, such as the FIFO 1Password's environments create for `.env`. Such an inode cannot be hardlinked into the injected copy, so it is skipped and the rest of the package still syncs [#&#8203;13550](https://github.com/pnpm/pnpm/issues/13550). `syncInjectedDepsAfterScripts` also no longer fails with `EEXIST` when a workspace package replaced a file with a directory of the same name since the injected copy was last synced. - `syncInjectedDepsAfterScripts` no longer fails with `ENOTDIR` when a workspace package replaced a directory with a file of the same name and the injected copy still held that directory's contents. - `syncInjectedDepsAfterScripts` now removes the bin link of a bin the script dropped. Previously only new bins were linked, so a build step that stopped declaring one left its shim behind, pointing at a command that was no longer there. - `syncInjectedDepsAfterScripts` now identifies a file by its device as well as its inode number. An inode number is only unique within one filesystem, so on its own it could match an unrelated file on another device and leave that path stale in the injected copy. - `pnpm store prune` no longer deletes the lockfile verification log. The log records which lockfile passed which supply-chain policies, so it stays valid across a prune of the store; keeping it lets the next install skip re-verifying an unchanged lockfile. - Widening a dependency's range no longer leaves the project on an older version. The lockfile update now points the project at the highest version of that dependency already in the lockfile that satisfies the new range — matching what a full resolution records — instead of keeping the locked version whenever it happened to satisfy, which could leave a duplicate behind. A range change that only an already-locked version satisfies is now also handled without re-resolving [#&#8203;13778](https://github.com/pnpm/pnpm/issues/13778). - `resolutionMode` is no longer ignored when `minimumReleaseAge` is in effect. `lowest-direct` and `time-based` pick the lowest satisfying version of a direct dependency again; previously any active release-age cutoff — including the built-in default — silently forced the highest, so `resolutionMode` only worked when `minimumReleaseAge: 0` was set explicitly [#&#8203;13752](https://github.com/pnpm/pnpm/issues/13752). - Adding a package to a workspace no longer forces a full re-resolution when every dependency it declares is already locked for a sibling. The lockfile update writes the new project's importer entry from the versions the lockfile already holds; a dependency no locked version satisfies still reaches the resolver [#&#8203;13696](https://github.com/pnpm/pnpm/issues/13696). - `pnpm config delete <key>` no longer fails with `ENOENT` when the config file it would edit does not exist. Clearing a setting that was never set is a no-op [#&#8203;13651](https://github.com/pnpm/pnpm/issues/13651). - Changing a `pnpm.overrides` entry to a version range now updates the lockfile in place when a version the lockfile already holds satisfies the range, instead of re-resolving the whole dependency graph. Only exact versions were handled before [#&#8203;13696](https://github.com/pnpm/pnpm/issues/13696). - Changing a parent-scoped `pnpm.overrides` entry (`"parent>child": "2.0.0"`) now updates the lockfile in place instead of re-resolving the whole dependency graph. Only the named parent's dependency moves; every other package keeps the version it had [#&#8203;13795](https://github.com/pnpm/pnpm/issues/13795). - Removing a dependency, or moving one to another already-locked version, no longer re-resolves the whole dependency graph just because some package resolves a peer with the same name. The lockfile update now compares the peer suffixes against the exact `name@version` the removal severed, so a suffix that names a different — still present — version of that dependency is left alone [#&#8203;13781](https://github.com/pnpm/pnpm/issues/13781). - Projects with a pnpmfile now use the fast lockfile update paths: an unchanged pnpmfile (proven by the recorded `pnpmfileChecksum`) no longer forces a full re-resolution for removals, dependency group moves, compatible range changes, and the other in-place lockfile rewrites [#&#8203;13696](https://github.com/pnpm/pnpm/issues/13696). - A lockfile entry whose resolution is unchanged no longer loses its recorded `deprecated` marker when a registry serves the package's metadata inconsistently — re-resolving to the same version keeps the deprecation instead of silently dropping the line [#&#8203;13846](https://github.com/pnpm/pnpm/issues/13846). - `pnpm prune` is now recursive by default inside a workspace, just like `pnpm install`. This fixes `pnpm prune --prod` in a workspace root emptying the `node_modules` directories of the other workspace projects, dropping the links to the workspace packages they depend on in production [#&#8203;13718](https://github.com/pnpm/pnpm/issues/13718). - A setting written in kebab-case in the global `config.yaml` is now reported instead of being silently ignored [#&#8203;13650](https://github.com/pnpm/pnpm/issues/13650). - `pnpm remove` no longer re-resolves the dependency graph. The removed dependency's entries are dropped from `pnpm-lock.yaml` and anything they made unreachable is pruned, without registry access. The install still falls back to a full resolution when a surviving package resolves a peer dependency through the removed one. - Removing a package from a workspace no longer forces a full re-resolution. The lockfile update drops the departed project's importer entry and prunes whatever only it depended on. A project that is still linked from a surviving project continues to be reported as an error [#&#8203;13696](https://github.com/pnpm/pnpm/issues/13696). - An install sharing a global virtual store no longer removes an incomplete package directory that another importer is still writing, which could fail with `failed to remove existing directory ... prior to swap: Directory not empty`. Such a directory is now repaired in place, and a package file left damaged by an interrupted install is restored instead of being kept. - `pnpm sbom` no longer emits components for optional platform-specific dependencies that cannot be installed on the current platform (for example, the native `@rolldown/binding-*` variants for other operating systems). Such packages are present in the lockfile but are never downloaded, so their license (and other metadata) could not be resolved and they appeared in the SBOM without one. `pnpm sbom --lockfile-only` still describes the whole lockfile graph, which is platform-independent by design. - An `ssh://` git dependency pointing at a bracketed IPv6 host, such as `ssh://[::1]/repo.git`, is resolved now. Its colons were read as an SCP-style path separator, which turned the address into `[:/1]` and left the specifier unresolvable. Applies to both the TypeScript CLI and pacquet. In the TypeScript CLI, an `ssh://` git dependency written without user info — `ssh://git.example.com/team/repo.git`, `git+ssh://git.example.com:2222/team/repo.git` — no longer fails with `TypeError: Cannot read properties of undefined (reading 'includes')`. Only the `user@host` form worked before. - `packageExtensions` is now validated when the configuration is read, so a malformed entry (for instance a dependency range set to `null`) fails with an actionable error instead of crashing later during peer dependency resolution [#&#8203;13756](https://github.com/pnpm/pnpm/issues/13756). - Projects using `resolutionMode: time-based` now benefit from the fast lockfile update paths. A removal, a dependency group move, or a compatible range change no longer forces a full re-resolution just because the lockfile carries a `time` field [#&#8203;13696](https://github.com/pnpm/pnpm/issues/13696). - An install that drops the last dependent of a patched package no longer updates the lockfile in place and succeeds silently. Removing a dependency, widening `ignoredOptionalDependencies`, or adding a removal override could each prune the package while the patch stayed configured; such an install now falls back to a full resolution, which reports the unused patch with `ERR_PNPM_UNUSED_PATCH`. Under `allowUnusedPatches`, where the lockfile update is kept, the same install now warns that the patch went unused instead of saying nothing [#&#8203;13827](https://github.com/pnpm/pnpm/issues/13827). <!-- 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.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 --> </details> <details> <summary>recharts/recharts (recharts)</summary> ### [`v3.10.1`](https://github.com/recharts/recharts/releases/tag/v3.10.1) [Compare Source](https://github.com/recharts/recharts/compare/v3.10.0...v3.10.1) #### What's Changed - fix(Pie): pass computed innerRadius/outerRadius to Label children via PolarLabelContextProvider by [@&#8203;0007aadil](https://github.com/0007aadil) in [#&#8203;7458](https://github.com/recharts/recharts/pull/7458) - chore(deps): bump immer from 11.1.9 to 11.1.15 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;7575](https://github.com/recharts/recharts/pull/7575) - fix(tooltip): fall back to index-based search when label-based search returns undefined for allowDuplicatedCategory=false by [@&#8203;hxy-asdw](https://github.com/hxy-asdw) in [#&#8203;7573](https://github.com/recharts/recharts/pull/7573) - fix(bar): keep barGap correct when maxBarSize clamps the bar width ([#&#8203;2774](https://github.com/recharts/recharts/issues/2774)) by [@&#8203;sobol-sudo](https://github.com/sobol-sudo) in [#&#8203;7582](https://github.com/recharts/recharts/pull/7582) #### New Contributors - [@&#8203;0007aadil](https://github.com/0007aadil) made their first contribution in [#&#8203;7458](https://github.com/recharts/recharts/pull/7458) - [@&#8203;hxy-asdw](https://github.com/hxy-asdw) made their first contribution in [#&#8203;7573](https://github.com/recharts/recharts/pull/7573) - [@&#8203;sobol-sudo](https://github.com/sobol-sudo) made their first contribution in [#&#8203;7582](https://github.com/recharts/recharts/pull/7582) **Full Changelog**: <https://github.com/recharts/recharts/compare/v3.10.0...v3.10.1> ### [`v3.10.0`](https://github.com/recharts/recharts/releases/tag/v3.10.0) [Compare Source](https://github.com/recharts/recharts/compare/v3.9.2...v3.10.0) #### What's Changed ##### Legend position Legend now supports `position` and `offset` props, same as Label and LabeList. This replaces the previous `align` and `verticalAlign` for a more convenient positioning, and fixes couple visual bugs too. See <https://recharts.github.io/en-US/examples/LegendPosition/> - Legend position and offset by [@&#8203;PavelVanecek](https://github.com/PavelVanecek) in [#&#8203;7564](https://github.com/recharts/recharts/pull/7564) ##### XAxis auto height XAxis now supports height="auto" prop, similar to YAxis width="auto". - feat(XAxis): support height="auto" to size the axis to its tick labels by [@&#8203;kimlj](https://github.com/kimlj) in [#&#8203;7570](https://github.com/recharts/recharts/pull/7570) ##### Other features - feat(Sankey): support accessibilityLayer, title and desc props by [@&#8203;MahinAnowar](https://github.com/MahinAnowar) in [#&#8203;7546](https://github.com/recharts/recharts/pull/7546) ##### Bugfixes - fix: clear stale active bar layer state by [@&#8203;pupuking723](https://github.com/pupuking723) in [#&#8203;7547](https://github.com/recharts/recharts/pull/7547) - fix(Brush): slide snaps back to original position on mouseup when start/endIndex are controlled by [@&#8203;MaksZhukov](https://github.com/MaksZhukov) in [#&#8203;7542](https://github.com/recharts/recharts/pull/7542) - fix(Tooltip): find the active sector in the angle-axis wrap-around gap by [@&#8203;MahinAnowar](https://github.com/MahinAnowar) in [#&#8203;7550](https://github.com/recharts/recharts/pull/7550) - fix(Brush): keep controlled startIndex/endIndex on data updates by [@&#8203;momomuchu](https://github.com/momomuchu) in [#&#8203;7530](https://github.com/recharts/recharts/pull/7530) - Fix Legend type by [@&#8203;PavelVanecek](https://github.com/PavelVanecek) in [#&#8203;7560](https://github.com/recharts/recharts/pull/7560) - fix(Label): pass computed position attributes to custom label content by [@&#8203;MahinAnowar](https://github.com/MahinAnowar) in [#&#8203;7549](https://github.com/recharts/recharts/pull/7549) - fix(CartesianAxis): skip renderedTicks dispatch when tick values are unchanged by [@&#8203;kimlj](https://github.com/kimlj) in [#&#8203;7565](https://github.com/recharts/recharts/pull/7565) - fix: prevent getBandSizeOfAxis from collapsing band size due to floating-point tick gaps by [@&#8203;xianjianlf2](https://github.com/xianjianlf2) in [#&#8203;7556](https://github.com/recharts/recharts/pull/7556) - fix(Area): connectNulls connects across stacked points where every series is null by [@&#8203;kimlj](https://github.com/kimlj) in [#&#8203;7566](https://github.com/recharts/recharts/pull/7566) #### New Contributors - [@&#8203;MahinAnowar](https://github.com/MahinAnowar) made their first contribution in [#&#8203;7546](https://github.com/recharts/recharts/pull/7546) - [@&#8203;MaksZhukov](https://github.com/MaksZhukov) made their first contribution in [#&#8203;7542](https://github.com/recharts/recharts/pull/7542) - [@&#8203;momomuchu](https://github.com/momomuchu) made their first contribution in [#&#8203;7530](https://github.com/recharts/recharts/pull/7530) - [@&#8203;kimlj](https://github.com/kimlj) made their first contribution in [#&#8203;7565](https://github.com/recharts/recharts/pull/7565) - [@&#8203;xianjianlf2](https://github.com/xianjianlf2) made their first contribution in [#&#8203;7556](https://github.com/recharts/recharts/pull/7556) **Full Changelog**: <https://github.com/recharts/recharts/compare/v3.9.2...v3.10.0> ### [`v3.9.2`](https://github.com/recharts/recharts/releases/tag/v3.9.2) [Compare Source](https://github.com/recharts/recharts/compare/v3.9.1...v3.9.2) #### What's Changed - docs: clarify custom labels and ticks need SVG elements by [@&#8203;ishaanlabs-gg](https://github.com/ishaanlabs-gg) in [#&#8203;7524](https://github.com/recharts/recharts/pull/7524) - chore(deps): bump immer from 11.1.8 to 11.1.9 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;7526](https://github.com/recharts/recharts/pull/7526) - fix(Sankey): avoid exponential depth traversal on dense graphs by [@&#8203;dm-gthb](https://github.com/dm-gthb) in [#&#8203;7479](https://github.com/recharts/recharts/pull/7479) #### New Contributors - [@&#8203;ishaanlabs-gg](https://github.com/ishaanlabs-gg) made their first contribution in [#&#8203;7524](https://github.com/recharts/recharts/pull/7524) - [@&#8203;dm-gthb](https://github.com/dm-gthb) made their first contribution in [#&#8203;7479](https://github.com/recharts/recharts/pull/7479) **Full Changelog**: <https://github.com/recharts/recharts/compare/v3.9.1...v3.9.2> ### [`v3.9.1`](https://github.com/recharts/recharts/releases/tag/v3.9.1) [Compare Source](https://github.com/recharts/recharts/compare/v3.9.0...v3.9.1) #### What's Changed - perf: optimize ScatterChart hover by reducing re-renders from O(n) to O(1) by [@&#8203;roy7](https://github.com/roy7) in [#&#8203;7133](https://github.com/recharts/recharts/pull/7133) - fix(YAxis): render explicit ticks when a non-literal domain can't resolve on empty data ([#&#8203;7362](https://github.com/recharts/recharts/issues/7362)) by [@&#8203;nlenepveu](https://github.com/nlenepveu) in [#&#8203;7393](https://github.com/recharts/recharts/pull/7393) - fix: avoid Sankey nodes overlapping skipped-depth links by [@&#8203;pupuking723](https://github.com/pupuking723) in [#&#8203;7471](https://github.com/recharts/recharts/pull/7471) - Add stacked bar chart with horizontal threshold line example by [@&#8203;nijuse](https://github.com/nijuse) in [#&#8203;7495](https://github.com/recharts/recharts/pull/7495) - fix(DefaultLegendContent): omit empty value from legend icon aria-label by [@&#8203;greymoth-jp](https://github.com/greymoth-jp) in [#&#8203;7501](https://github.com/recharts/recharts/pull/7501) - chore(deps): bump immer from 10.2.0 to 11.1.8 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;7452](https://github.com/recharts/recharts/pull/7452) - fix(getNiceTickValues): remove trailing duplicate tick when allowDecimals=false by [@&#8203;JSap0914](https://github.com/JSap0914) in [#&#8203;7482](https://github.com/recharts/recharts/pull/7482) - Fix/per graphical item formatter prop by [@&#8203;shreedharbhat98](https://github.com/shreedharbhat98) in [#&#8203;7287](https://github.com/recharts/recharts/pull/7287) #### New Contributors - [@&#8203;pupuking723](https://github.com/pupuking723) made their first contribution in [#&#8203;7471](https://github.com/recharts/recharts/pull/7471) - [@&#8203;nijuse](https://github.com/nijuse) made their first contribution in [#&#8203;7495](https://github.com/recharts/recharts/pull/7495) - [@&#8203;greymoth-jp](https://github.com/greymoth-jp) made their first contribution in [#&#8203;7501](https://github.com/recharts/recharts/pull/7501) - [@&#8203;JSap0914](https://github.com/JSap0914) made their first contribution in [#&#8203;7482](https://github.com/recharts/recharts/pull/7482) **Full Changelog**: <https://github.com/recharts/recharts/compare/v3.9.0...v3.9.1> </details> <details> <summary>typescript-eslint/typescript-eslint (typescript-eslint)</summary> ### [`v8.72.2`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8722-2026-11-09) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.72.1...v8.72.2) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.72.2) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.72.1`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8721-2026-10-26) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.72.0...v8.72.1) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.72.1) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.72.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8720-2026-10-19) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.71.2...v8.72.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.72.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.71.2`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8712-2026-10-12) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.71.1...v8.71.2) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.71.2) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.71.1`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8711-2026-10-05) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.71.0...v8.71.1) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.71.1) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.71.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8710-2026-09-28) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.70.1...v8.71.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.71.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.70.1`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8701-2026-09-21) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.70.0...v8.70.1) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.70.1) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.70.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8700-2026-09-07) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.69.0...v8.70.0) ##### 🩹 Fixes - **eslint-plugin:** \[no-deprecated] report deprecated imported values used in object shorthand properties ([#&#8203;12780](https://github.com/typescript-eslint/typescript-eslint/pull/12780)) ##### ❤️ Thank You - Ulrich Stark [@&#8203;ulrichstark](https://github.com/ulrichstark) See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.70.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.69.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8690-2026-08-31) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.68.0...v8.69.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.69.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.68.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8680-2026-08-24) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.67.0...v8.68.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.68.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.67.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8670-2026-08-10) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.66.0...v8.67.0) ##### 🚀 Features - **typescript-eslint:** export basic globs for using tseslint ([#&#8203;12105](https://github.com/typescript-eslint/typescript-eslint/pull/12105)) ##### ❤️ Thank You - Claude Sonnet 5 - Evyatar Daud [@&#8203;StyleShit](https://github.com/StyleShit) - Josh Goldberg - Josh Goldberg ✨ - Kirk Waiblinger [@&#8203;kirkwaiblinger](https://github.com/kirkwaiblinger) See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.67.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.66.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8660-2026-08-03) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.65.0...v8.66.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.66.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.65.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8650-2026-07-20) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.64.0...v8.65.0) ##### 🚀 Features - add warning when TS 7 is detected ([#&#8203;12529](https://github.com/typescript-eslint/typescript-eslint/pull/12529)) ##### ❤️ Thank You - Josh Goldberg ✨ - Kirk Waiblinger [@&#8203;kirkwaiblinger](https://github.com/kirkwaiblinger) See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.65.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.64.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8640-2026-07-13) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.63.0...v8.64.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.64.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.63.0`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8630-2026-07-06) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.62.1...v8.63.0) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.63.0) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. ### [`v8.62.1`](https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8621-2026-06-29) [Compare Source](https://github.com/typescript-eslint/typescript-eslint/compare/v8.62.0...v8.62.1) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. See [GitHub Releases](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.1) for more information. You can read about our [versioning strategy](https://typescript-eslint.io/users/versioning) and [releases](https://typescript-eslint.io/users/releases) on our website. </details> --- ### Configuration 📅 **Schedule**: (in timezone Europe/Berlin) - 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. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- 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:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDQuMyIsInVwZGF0ZWRJblZlciI6IjQ0LjIyMi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
chore(deps): update dependency typescript-eslint to v8.62.1
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 7s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 11s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m3s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m45s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
75d2448702
Renovate force-pushed renovate/frontend-non-major-dependencies from 75d2448702
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 7s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 11s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m3s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m45s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 7196ecfd98
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 13s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m11s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-06-30 18:01:31 +02:00
Compare
Renovate changed title from chore(deps): update dependency typescript-eslint to v8.62.1 to fix(deps): update frontend non-major dependencies 2026-06-30 18:01:33 +02:00
Renovate force-pushed renovate/frontend-non-major-dependencies from 7196ecfd98
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 13s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m11s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 6847adde3a
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 13s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 52s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m32s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-04 06:01:42 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 6847adde3a
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 13s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 52s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m32s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 37cd9307d4
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 12s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 45s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m23s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-04 22:20:43 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 37cd9307d4
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 12s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 45s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m23s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to e1d3a97931
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 43s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m26s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-06 22:02:18 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from e1d3a97931
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 43s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m26s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to a6c2172672
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 13m8s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-10 02:02:28 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from a6c2172672
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 13m8s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to fe6b0a4082
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 8s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m27s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 5m0s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-12 02:17:06 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from fe6b0a4082
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 8s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m27s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 5m0s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 51b7659714
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 8s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 42s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m36s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-13 22:01:57 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 51b7659714
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 8s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 42s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m36s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 68dde76360
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 43s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m28s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-14 02:02:03 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 68dde76360
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 43s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m28s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 9e5209021d
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 27s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 3m7s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 4m30s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-16 06:03:17 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 9e5209021d
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 27s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 3m7s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 4m30s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 57f29eb19b
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 29s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m2s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 9m6s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-18 02:03:04 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 57f29eb19b
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 29s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m2s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 9m6s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 978d6d946f
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 25s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m41s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m17s
2026-07-18 22:01:53 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 978d6d946f
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 25s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m41s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m17s
to 466394bb5b
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 26s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m52s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m14s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-20 02:01:50 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 466394bb5b
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 26s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m52s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m14s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 319acfcacc
Some checks failed
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 23s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m8s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m42s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-20 22:02:00 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 319acfcacc
Some checks failed
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 23s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m8s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m42s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to e3d089576f
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 24s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m2s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m40s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-21 02:01:44 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from e3d089576f
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 24s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m2s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m40s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to d80710fe01
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 27s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m5s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 9m33s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-23 02:03:09 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from d80710fe01
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 27s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m5s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 9m33s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to e4dd5bf7d9
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 25s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m16s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 7m3s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-23 22:03:27 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from e4dd5bf7d9
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 25s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m16s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 7m3s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 242dcb31f9
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 8s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 39s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m16s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-25 18:03:05 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 242dcb31f9
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 8s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 39s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m16s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 0384866439
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m38s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 8m14s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-07-29 18:03:12 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 0384866439
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m38s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 8m14s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 556efe8912
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 17s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 6m37s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-03 18:03:05 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 556efe8912
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 17s
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 6m37s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 74f02369a3
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m13s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 3m13s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-03 22:02:11 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 74f02369a3
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m13s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 3m13s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 16d2209abd
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 30s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m9s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 9m18s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-09 18:02:05 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 16d2209abd
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 30s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m9s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 9m18s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 0e627f96ee
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 37s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m17s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 3m29s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-10 22:02:12 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 0e627f96ee
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 37s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m17s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 3m29s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to cd2ee967f1
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 40s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m13s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 7m22s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-15 22:02:33 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from cd2ee967f1
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 40s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m13s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 7m22s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 154ab637b2
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 18s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 29s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m49s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 11m16s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-23 18:04:03 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 154ab637b2
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 18s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 29s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m49s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 11m16s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 6de5a9166a
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 31s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 57s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m27s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-24 22:08:53 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 6de5a9166a
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 31s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 57s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m27s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 40439337bc
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 36s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 52s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m30s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-25 18:07:27 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 40439337bc
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 36s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 52s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m30s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 1c1b41ad58
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 26s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 56s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m8s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m49s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-08-31 22:01:40 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 1c1b41ad58
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 26s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 56s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m8s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m49s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 0b73ffe663
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 56s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m39s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-01 06:01:56 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 0b73ffe663
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 56s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m39s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to b8e10f7d90
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 17s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m11s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 10m58s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-07 06:02:00 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from b8e10f7d90
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 17s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m11s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 10m58s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 95434147b3
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 14s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 59s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m58s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-08 02:01:22 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 95434147b3
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 9s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 14s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 59s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m58s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 7f203096a4
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m15s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 7m3s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-13 02:01:20 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 7f203096a4
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m15s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 7m3s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to e75734a30f
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 16s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m57s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 10m9s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-21 02:01:39 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from e75734a30f
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 16s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m57s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 10m9s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 15ec3baae1
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 59s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m48s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-21 22:01:15 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 15ec3baae1
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 15s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 59s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 1m48s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 19754677ad
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m24s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 7m23s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-25 14:01:06 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 19754677ad
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m24s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 7m23s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 5508418ce7
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 17s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m39s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m21s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-28 10:01:08 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 5508418ce7
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 17s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m39s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m21s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to e260889c9b
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m18s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m57s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-28 22:01:40 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from e260889c9b
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m18s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m57s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to ee2edae2c5
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m49s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 10m43s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-09-30 18:01:06 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from ee2edae2c5
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 18s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m49s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 10m43s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to c2db9b54d6
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 22s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m58s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m30s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-04 02:01:52 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from c2db9b54d6
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 22s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m58s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 8m30s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 0687057df1
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 19s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m9s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m8s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-05 22:01:16 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 0687057df1
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 19s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m9s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m8s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 1b4e5324f3
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 19s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m22s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m35s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-06 10:01:24 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 1b4e5324f3
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 11s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 19s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m22s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m35s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to b71b3a9136
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m31s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m45s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-12 22:01:29 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from b71b3a9136
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 20s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m31s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m45s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to e5cd17bda1
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 16s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m56s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 6m28s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-15 18:03:46 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from e5cd17bda1
All checks were successful
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 16s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m56s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Successful in 6m28s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 209cd36579
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 41s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 15m58s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 15m59s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Failing after 16m42s
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been cancelled
2026-10-19 22:02:30 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 209cd36579
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 41s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 15m58s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 15m59s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Failing after 16m42s
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been cancelled
to 5290ca429c
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 12m33s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 12m33s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Failing after 12m51s
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been cancelled
2026-10-21 14:01:25 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 5290ca429c
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 14s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 12m33s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 12m33s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Failing after 12m51s
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been cancelled
to bb24ae86f0
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 43s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 3m46s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 9m31s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-23 02:01:29 +02:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from bb24ae86f0
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 16s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 43s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 3m46s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 9m31s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to a404daf771
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m17s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Failing after 2m59s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-26 21:02:15 +01:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from a404daf771
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m17s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Failing after 2m59s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 6ec1fff73b
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 47s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m49s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 3m12s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-27 05:01:40 +01:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 6ec1fff73b
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 15s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 47s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m49s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 3m12s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 5be255212e
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 43s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 3m29s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 9m5s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-10-30 17:01:17 +01:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 5be255212e
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 43s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 3m29s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 9m5s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 2cc7d53981
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 32s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 8m27s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-11-05 05:01:11 +01:00
Compare
Renovate force-pushed renovate/frontend-non-major-dependencies from 2cc7d53981
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 13s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 32s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 2m48s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 8m27s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
to 9f89204920
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 27s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m13s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m0s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
2026-11-09 21:01:20 +01:00
Compare
Some checks failed
CI/CD Workflow / Detect changed paths (pull_request) Successful in 12s
CI/CD Workflow / Test Backend (Go) (pull_request) Has been skipped
CI/CD Workflow / Test Postgres Store (pull_request) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Has been skipped
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 27s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Failing after 1m13s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 2m0s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
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/frontend-non-major-dependencies:renovate/frontend-non-major-dependencies'
git switch 'renovate/frontend-non-major-dependencies'

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/frontend-non-major-dependencies'
git switch 'renovate/frontend-non-major-dependencies'
git rebase 'main'
git switch 'main'
git merge --ff-only 'renovate/frontend-non-major-dependencies'
git switch 'renovate/frontend-non-major-dependencies'
git rebase 'main'
git switch 'main'
git merge --no-ff 'renovate/frontend-non-major-dependencies'
git switch 'main'
git merge --squash 'renovate/frontend-non-major-dependencies'
git switch 'main'
git merge --ff-only 'renovate/frontend-non-major-dependencies'
git switch 'main'
git merge 'renovate/frontend-non-major-dependencies'
git push origin 'main'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kreativmonkey/goloom!122
No description provided.