Update all non-major dependencies #51

Open
renovatebot wants to merge 1 commit from renovate/all-minor-patch into main
Collaborator

This PR contains the following updates:

Package Type Update Change Age Confidence
docker.io/haproxy (source) Kustomization patch 3.4.5 → 3.4.6 age confidence
ghcr.io/immich-app/immich-machine-learning Kustomization patch v3.2.2 → v3.2.4 age confidence
ghcr.io/immich-app/immich-server Kustomization patch v3.2.2 → v3.2.4 age confidence
pnpm (source) packageManager minor 12.6.0 → 12.8.1 age confidence

Release Notes

immich-app/immich (ghcr.io/immich-app/immich-machine-learning)

v3.2.4

Compare Source

It's been a while since we last had to sacrifice a release. Let's hope v3.2.3 was a good sacrifice for v3.3, which is right around the corner!

Just another small patch that primarily fixes the memory leak people have observed through a dependency update.

What's Changed
🐛 Bug fixes

Full Changelog: https://github.com/immich-app/immich/compare/v3.2.2...v3.2.4

pnpm/pnpm (pnpm)

v12.8.1: pnpm 12.8.1

Compare Source

pnpm 12.8.1 fixes pnpm install --frozen-lockfile rejecting lockfiles with injected workspace packages that have peers, restores the executable bit on files of local directory dependencies, makes pnpm dedupe converge, and uses less CPU on many-core machines.

Patch Changes
  • pnpm install --frozen-lockfile no longer rejects a freshly generated lockfile when an injected workspace package has peer dependencies #​16332.

  • Executable files in a file: directory dependency or an injected workspace package keep their executable bit again. Since 12.8.0, pnpm installed these files without the permissions they have in their project.

  • pnpm dedupe now reaches a stable lockfile when a package's peer suffix is long enough to be hashed. Before, each run could switch that package's key between the hashed and the spelled-out suffix, so pnpm dedupe --check always failed #​16331.

  • pnpm install --frozen-lockfile, the default in CI, now uses less CPU on machines with more than 8 cores. Warm installs on many-core Windows machines got up to 10% faster. Frozen installs now link with at most 16 worker threads.

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

  • pnpm update -g --latest now upgrades globally installed packages beyond their saved version ranges #​16320.

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

v12.8.0: pnpm 12.8

Compare Source

pnpm 12.8.0 warns when pnpm pack or pnpm publish would ship a .env file that files does not list, installs sharedWorkspaceLockfile: false workspaces concurrently, applies every setting passed as --config.<name>=<value>, and no longer leaves the Windows terminal stuck after Ctrl+C in a script.

Minor Changes
  • pnpm pack and pnpm publish now warn when the tarball includes a .env or .env.* file that the files field of package.json does not list. Templates such as .env.example are not reported. List the file in files to publish it on purpose, or exclude it in .npmignore or .gitignore #​7826.

  • pnpm pack now honors --silent, --reporter=silent, and --loglevel=silent to hide the tarball contents and summary. With --json, lifecycle script output and the final JSON output remain visible #​10297.

Patch Changes
Installing packages
  • Installing through a pnpr server now records the pnpmfile checksum in the lockfile, so a later pnpm install --frozen-lockfile accepts that lockfile #​14460. 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.

    Installing through a pnpr server also links a workspace project at the directory its publishConfig.directory names. A server that does not forward the setting makes the install fail with ERR_PNPM_PNPR_PUBLISH_DIRECTORY_MISMATCH, so pnpm never writes a lockfile that points at the wrong directory. The server rejects a publishConfig.directory that points outside its project.

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

  • A git-hosted dependency that is a pnpm workspace with no committed lockfile is now detected as a pnpm project #​14011.

  • 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 --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. The error also carries the ERR_PNPM_NO_OFFLINE_META code. pnpm cache prune --help now says that pnpm 11.26 and earlier, and pnpm 12.3 and earlier, depend on the directories it removes #​15656.

  • Running pnpm install now refreshes dependencies when a package declared with a local file: directory changes its dependencies #​4623.

  • A repeat pnpm install now keeps its fast up-to-date check when an override replaces a declared local file: dependency #​12892.

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

  • 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. On Windows, the install also no longer fails with "Access is denied" when another project's copy of a shared dependency links to the deleted directory.

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

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

Resolving and linking dependencies
  • pnpm install no longer aborts on a failed allocation of many gigabytes when peer dependency ranges combine overlapping || alternatives #​15867.

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

  • An npm: alias written by overrides now stays in place when a change elsewhere makes pnpm re-resolve the aliased dependency. Before, pnpm could look up the alias name at the aliased version, which failed with ERR_PNPM_NO_MATCHING_VERSION or locked an unrelated package #​16309.

  • 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 dedupe no longer changes the lockfile on every run when a nested peer dependency is provided through an npm alias #​15709.

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

  • pnpm install retries registry metadata fetches that fail with a timeout, a dropped connection, or an interrupted response body before it applies trustPolicy or minimumReleaseAge. A transient fetch failure is not reported as TRUST_DOWNGRADE or MINIMUM_RELEASE_AGE_VIOLATION #​12031.

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

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

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

Lockfiles and frozen installs
  • pnpm install --frozen-lockfile now works on a detached HEAD when gitBranchLockfile is enabled. The install 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 --frozen-lockfile now accepts a lockfile that has no importer entry for a workspace package without dependencies. Such a package added after the lockfile was written made the install fail with ERR_PNPM_PACKAGE_MANAGER_NO_IMPORTER #​15875.

  • pnpm install now fails with ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY when an importer references a dependency version that has no snapshot entry. Before, the install succeeded and left a node_modules symlink pointing at a missing virtual-store directory #​14764.

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

  • With gitBranchLockfile enabled, each emoji or other character outside the Basic Multilingual Plane in a branch name now becomes !! in the lockfile name. Before, each such character became one !.

Workspaces and filtering
  • pnpm install in a workspace with sharedWorkspaceLockfile: false now installs projects concurrently, up to workspaceConcurrency at a time #​14480. A project is resolved, fetched, and written to its virtual store without waiting for the workspace projects it depends on. It waits for them only before it links its dependencies and runs its lifecycle scripts, so its scripts still run after theirs. A project with a preinstall or pnpm:devPreinstall script, or with an injected or file: workspace dependency, waits for its workspace dependencies before it starts.

    The installs of the projects also share their package metadata, lockfile verification, and store caches, so they use less CPU and memory when several projects depend on the same packages. An install with a pnpmfile no longer starts an extra Node.js process when the pnpmfile has no preResolution hook.

  • With enableGlobalVirtualStore and sharedWorkspaceLockfile: false, each project now keeps its current lockfile and its hidden hoisted dependencies in its own node_modules/.pnpm. Before, every project wrote them to the workspace root's node_modules/.pnpm, so each repeat install treated the other projects' packages as its own and relinked them #​14480.

  • pnpm rebuild, pnpm approve-builds, and pnpm ignored-builds now work on the current project's node_modules when they run inside a project of a workspace with sharedWorkspaceLockfile: false. They used to read the workspace root's node_modules, so pnpm rebuild did not rebuild the project's dependencies and created a second virtual store at the workspace root #​9402.

  • 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. It also no longer fails with ERR_PNPM_CMD_SHIM_RESOLVE_PATH when such a package has a bin field and its publishConfig.directory does not exist yet.

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

  • An in-place edit to the source of an injected workspace package now shows up in its injected copy, unless a build writes to that package or packageImportMethod is set. pnpm hardlinks such packages under the default import method #​4410. Scripts listed in syncInjectedDepsAfterScripts now update injected dependencies while they run, so a watcher on the injected package, such as a dev server, sees each change before the script exits.

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

  • Workspace discovery prunes dot-prefixed directories, so a packages pattern such as ** no longer matches projects inside .cache and other hidden directories #​16250.

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

Store and caches
  • 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.

  • 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, so hard-linked copies in other projects are healed at the same time. On Windows the repair still replaces the file, so other projects are healed on their next install #​3445.

  • pnpm install now reports a full store at once when writing package files fails. It no longer retries the tarball #​8581.

  • pnpm now warns when it cannot hard link packages from an existing store in the pnpm home directory and falls back to 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.

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

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

  • With enableGlobalVirtualStore, an install into a fresh node_modules no longer runs the build scripts of a dependency whose global virtual store slot an earlier install already built. pnpm rebuild still runs them #​14480.

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

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

  • 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 install honors Cache-Control for dependencies named with an http: or https: tarball URL. A fresh response is taken from the store with no request, and a stale one is revalidated with If-None-Match #​15648.

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. Before, pnpm 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 with nodeLinker: hoisted now applies a patch once to each copy of a patched dependency in a workspace. Before, a copy that several workspace projects shared could receive the patch twice and end up with the patched content duplicated #​7565.

  • pnpm install and pnpm fetch now fail with ERR_PNPM_PATCH_NOT_FOUND when a patch file listed in patchedDependencies does not exist #​5268.

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

Adding, updating, and removing dependencies
  • 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.

  • pnpm add --save-types no longer adds a @types/* package whose resolved version is deprecated. DefinitelyTyped publishes such stubs for packages that ship their own types, such as @types/typescript for typescript #​15636.

  • pnpm version, pnpm add, and pnpm pkg set keep JSON5 style when they update package.json5. ASCII identifier keys stay unquoted, strings keep JSON5 quotes, and indented files keep trailing commas #​15717.

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.

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

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

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

  • With enableGlobalVirtualStore, dependency build scripts now see the workspace root's node_modules/.bin, as they do with a local virtual store. A postinstall script that runs node finds the Node.js installed by devEngines.runtime and no longer fails with "command not found" on machines without a system Node.js #​15652. Dependency build scripts also see the bins of privately hoisted dependencies.

  • Dependency install scripts now find the node-gyp bundled with pnpm when pnpm runs through a symlink, such as node_modules/.bin/pnpm or the pnpm that npm install -g pnpm links. They used to fail with node-gyp: command not found on macOS #​15694.

  • pnpm run and lifecycle scripts now set npm_config_node_gyp to the bundled node-gyp entry point. Tools that read the variable resolve the same node-gyp pnpm builds with. An npm_config_node_gyp value the environment already sets is kept as is #​16270.

  • Scripts now see the npm_command environment variable that npm sets. It holds run-script when the command runs a script, and the command's own name otherwise #​16265.

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

  • pnpx --version and pnpm dlx --version now print the pnpm version. Other unknown options before the command are reported as errors. Before, pnpm tried to download a package named after the option #​16259.

  • pnpm dlx now keeps the virtual store of its cached installs in node_modules/.pnpm, like every other install #​13955. pnpm pack-app now names the manifest of its runtime install directory pnpm-pack-app-<target>.

Publishing, packing, and deploying
  • pnpm pack and pnpm publish now ship a file that the files field names even when another entry excludes the directory holding it. For example, ["**", "!dist", "dist/index.d.ts"] ships dist/index.d.ts #​16213.

  • pnpm pack prunes a directory that a files field exclusion names, such as !**/test, excluding the directory and its contents from the packed package #​15738.

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

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

Configuration and pnpmfile hooks
  • Every setting pnpm supports can now be set with --config.<name>=<value> on the command line, not only the ones whose command also carries a matching flag. Before, pnpm install --config.frozen-lockfile=true dropped the setting and rewrote pnpm-lock.yaml as though the install had not been frozen #​16276.

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

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

  • pnpm now fails with ERR_PNPM_AUTH_INVALID_BASE64 when a registry's _password in .npmrc is not valid base64. Before, it sent the value as the raw password. A username or _password left empty, for example by an unset environment variable, now supplies no credential #​16273.

  • proxy=false now turns proxying off even when HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY is set. pnpm no longer sends requests through a proxy named only in ALL_PROXY.

  • pnpm install now runs the install hooks of a config dependency plugin's pnpmfile, including readPackage, afterAllResolved, and custom resolvers. Its pnpmfile is also counted in pnpmfileChecksum. Before, only the plugin's updateConfig hook ran, so a plugin could not change the resolved dependencies.

  • A pnpmfile fetchers hook now runs once per package on a fresh install when it handles a resolution with a custom type or delegates a git-hosted one to the same subdirectory #​15584. These packages were fetched a second time for installation, so the installed files could come from a different archive than the one their dependencies were read from. The hook also no longer runs twice when a resolvers hook returns a tarball resolution without a manifest #​15025.

  • pnpm install now re-fetches a package from a custom resolver when the integrity of its resolution changes, with or without enableGlobalVirtualStore. It used to update the lockfile but keep the old files in node_modules #​15670.

  • pnpm install now rejects invalid results from a readPackage hook. A hook that returns a non-object value fails with ERR_PNPM_BAD_READ_PACKAGE_HOOK_RESULT #​15730. A hook that sets a dependency range to a value other than a string, such as undefined, fails with an error that names the dependency, the package and the pnpmfile. Delete the property to remove a dependency #​15705.

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.

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

  • On arm64 musl Linux, such as Alpine on ARM, switching to a pinned pnpm older than 12 now runs the JavaScript pnpm package. The standalone executable of those versions crashed at startup on that platform #​10443.

  • Global shims such as node now work when pnpm runs through a relative symlink, as with a Homebrew install. They were copies of that symlink and did not resolve from the global bin directory #​15691.

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

Windows
  • Interrupting a script with Ctrl+C on Windows no longer leaves the terminal stuck #​14860. A script that runs through a batch shim, as vite dev does through vite.CMD, made cmd.exe wait forever on its "Terminate batch job (Y/N)?" answer, and every following keystroke went to that prompt. pnpm now ends a cmd.exe script shell once it has sat for a second after the interrupt with nothing running under it. A script that takes longer to shut down is still waited for. A second Ctrl+C ends the script's shell at once.

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

  • The Windows pnpm.exe runs on a clean Windows install that does not have the Visual C++ Redistributable. It used to exit immediately on startup because that runtime was missing #​15723.

  • 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. Command shims also run tools whose paths contain non-ASCII characters #​6999, including the PowerShell shims in Windows PowerShell 5.1 #​16217.

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

  • On Windows, installing pnpm with npm inside a project now writes node_modules/.bin shims that run pnpm.exe. A global install with npm install --location=global now gets the same shims as npm install -g #​15688.

  • pnpm install no longer fails with ERR_PNPM_WORKSPACE_INVALID_GLOB on Windows for a wildcard pattern such as plugins/*/* in pnpm-workspace.yaml when the workspace is on a different drive than the pnpm cache or state directory #​16239.

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

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

  • pnpm setup on Windows no longer panics when an unrelated environment variable has a name containing a non-ASCII character. It skips that variable #​15684.

  • 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. Before, it showed the directory pnpm wanted to set.

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

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

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

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

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.

  • When a dependency fails to resolve, the error now shows the cause. For example, a Node.js runtime download behind a proxy that re-signs TLS now reports invalid peer certificate: UnknownIssuer #​9556.

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

  • Lockfile verification now fails with ERR_PNPM_TARBALL_URL_MISMATCH, ERR_PNPM_TARBALL_REVISION_MISMATCH, or ERR_PNPM_MISSING_NAMED_REGISTRY when every rejected entry failed that check. These failures were reported as the generic ERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATION.

  • 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 install no longer prints an extra Progress: line after the progress line is marked done #​16184.

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

v12.7.0: pnpm 12.7

Compare Source

pnpm 12.7.0 ships with .nvmrc and .node-version support in the global node shim, pnpm install --allow-build, pnpm publish --publish-wait-timeout, and pnpm-workspace.yaml created from the workspaces field. pnpm install --force no longer installs optional dependencies built for other platforms. This release also carries security fixes for bin shims on Nix, for lifecycle scripts of packages in a storeDir inside the workspace, and for userAgent placeholders in pnpm-workspace.yaml.

Minor Changes
  • pnpm install --force now keeps skipping optional dependencies whose os, cpu or libc do not match the host. It still refetches every package and lifts engineStrict. The new forceIgnoresPlatform setting restores the previous behaviour, installing optional dependencies of every platform under --force #​6133.

  • The global node shim created by pnpm now uses the Node.js version from the nearest .nvmrc or .node-version file when the project does not declare a Node.js runtime in devEngines.runtime or engines.runtime #​4471. The nearest directory with a Node.js runtime declaration decides the version. Within one directory, package.json takes precedence over .node-version, which takes precedence over .nvmrc. An .nvmrc value that only nvm can act on, such as system or a custom alias, is ignored.

  • pnpm install now supports the --allow-build option to selectively allow or deny package lifecycle scripts and record them in pnpm-workspace.yaml #​15388.

  • Added pnpm publish --publish-wait-timeout <milliseconds> to wait for published versions and their tarballs to become available from the registry. Set publishWaitTimeout in pnpm-workspace.yaml to configure a default. A value of 0 disables the check.

    Recursive publishing confirms availability before publishing dependent packages. If confirmation times out, the command fails.

    When pnpm publish -r --report-summary fails after some uploads were accepted, the summary file now lists those packages.

  • pnpm install now creates pnpm-workspace.yaml from the workspaces field of the root package.json when the repository has no pnpm-workspace.yaml. The projects the field lists are linked on that same install. An existing pnpm-workspace.yaml is never changed. With --ignore-workspace, no file is created. If the workspaces field later differs from packages in pnpm-workspace.yaml, pnpm prints a warning #​2255.

  • When a project pins a pnpm version or a runtime that another pnpm process is installing at that moment, pnpm now waits a few seconds and then installs and runs a private copy of its own. It used to wait up to five minutes and then use the shared install directory without the lock. The private copy is removed once the command has run. pnpm store prune removes any private copy that a killed process left behind #​15413.

  • pnpm now keeps the blank lines between entries of package.json when it updates the file, for example on pnpm add #​5602.

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.

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

  • pnpm no longer treats manifests inside its store, cache, state, or modules directories as workspace projects. Before, a storeDir inside the workspace could let lifecycle scripts of packages in the store run without allowBuilds approval #​15033.

  • Packages that run a lifecycle script are no longer hard-linked into the virtual store, so a build script can no longer rewrite the workspace source of an injected package or the store copy it was imported from #​15483.

Installing packages
  • Fixed pnpm install, pnpm add, pnpm remove, and pnpm peers check running out of memory when many packages share a missing peer dependency. This mostly affected projects with autoInstallPeers: false #​15362.

  • pnpm no longer hangs for up to 5 minutes after a pnpm process was killed while setting up the pnpm version pinned in packageManager or devEngines #​15360, #​15393. The killed process left behind a lock that every later pnpm command in the project waited on. pnpm now detects that the process holding a lock is gone and takes the lock over at once. The same applies to the locks pnpm takes while installing a managed runtime or writing the global bin directory. Two pnpm processes that are both still running keep waiting for each other as before.

  • Requests to a registry or tarball server whose TLS certificate fails verification now fail at once. Such requests were retried for more than a minute without any output #​9134.

  • On macOS, pnpm now falls back to its bundled CA roots when system trust evaluation is unavailable, such as in a sandbox or when macOS cannot create an SSL policy for a registry connection. Installs failed or crashed on the first registry request in that case. Custom ca certificates are now honored directly #​15329, #​14461.

  • pnpm install now caps concurrent connections to a proxy at 50 sockets by default #​15280. It also immediately retries transient connection resets when downloading package archives.

  • pnpm install now reuses a package already present in the store when an existing lockfile entry satisfies the dependency, avoiding registry requests that fail without authorization #​2522.

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

  • pnpm install now installs the new version of a local tarball dependency whose file was replaced at the same path #​2437. pnpm install --frozen-lockfile rejects such a changed tarball, even when the previous archive contents are in the store #​1889.

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

  • pnpm install now applies patches produced by pnpm patch-commit when an edit removes the trailing lines of a file along with its newline. The install no longer fails with ERR_PNPM_INVALID_PATCH ("expected end of hunk") #​12451.

  • pnpm install now preserves existing node_modules directories when a cross-device move reports EXDEV #​14504.

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

  • 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 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 uses less CPU when it links packages from a warm store. On Windows, a warm install could take several times longer than with pnpm 11 #​15439.

  • pnpm install now runs node --version once per run. A workspace whose projects keep their own lockfiles (sharedWorkspaceLockfile: false) previously ran the probe once or twice for every project, and on macOS the concurrent launches waited on each other, so a project could wait several seconds before its linking started.

  • A repeat pnpm install --frozen-lockfile with nodeLinker: hoisted in a workspace no longer re-links node_modules when nothing changed.

  • Custom fetcher hooks no longer run a second time during installation when an archive was already fetched during dependency resolution #​15025.

  • Fixed a package resolved by a resolvers pnpmfile hook installing without its own dependencies. This happened when the hook returned no manifest and a fetchers hook handled the resolution #​15552.

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

  • pnpm prune --prod and production installs now remove devDependencies when lockfile: false is configured #​2677.

  • 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 install no longer skips optional dependencies that the Node.js version locked for a devEngines.runtime range supports, when the range uses onFail: download. An explicitly set nodeVersion still takes priority #​14628.

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

  • pnpm now detects the same CI environments as pnpm 11, including AWS CodeBuild, which does not set CI. On these services pnpm install uses a frozen lockfile by default and fails with ERR_PNPM_OUTDATED_LOCKFILE when the lockfile is outdated.

Resolving and linking dependencies
  • 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.

  • 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 now re-resolves a dependency when its manifest range is updated from a prerelease to a stable version. The lockfile previously retained the prerelease version and caused --frozen-lockfile to fail #​15528.

  • 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 and pnpm peers check now use local tarball packages' actual versions when checking peer dependencies. Compatible packages no longer fail with strictPeerDependencies enabled.

  • pnpm peers check and the install-time peer dependency check now resolve peer dependencies from the workspace root when resolvePeersFromWorkspaceRoot is enabled #​14982.

  • autoDedupe and pnpm dedupe now move transitive dependencies to the version a catalog: dependency pins, as they already did for versions written directly in package.json. Previously they could move those dependencies to a higher version and keep both versions in the lockfile.

  • pnpm dedupe now produces a stable lockfile when a dependency's range matches both a direct dependency and an npm: alias of the same package. The dependency resolves to the version of the direct dependency. Repeated runs previously alternated between two lockfiles #​15588.

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

  • Tarball URLs recorded in the lockfile now strip default HTTP and HTTPS ports (:80 and :443) #​15539.

  • node_modules/.package-map.json no longer contains entries that point at directories that do not exist. Such entries appeared for packages installed only with peer dependencies, most visibly with enableGlobalVirtualStore #​14938.

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

  • 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 no longer puts a dependency's bin on PATH for that dependency's own lifecycle scripts before the bin's file exists. pnpm links such a bin after the dependency's build has run. It also removes such a bin left by an earlier install. This fixes installing the node package on Windows #​15501.

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

  • Bin linking leaves workspace and linked dependency files outside node_modules unchanged. Already executable bin files no longer receive redundant permission changes.

Workspaces and filtering
  • pnpm install now finds workspace projects reached through a symlink, such as a packages directory that links to a folder outside the workspace. It 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.

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

  • pnpm install now copies the output of a workspace package's own prepare, install, or postinstall script into the injected copies of that package. Before, the injected copies kept only the files that existed before the script ran. syncInjectedDepsAfterScripts now also works when modulesDir is set #​9464.

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

  • A modulesDir with several path segments, such as www/modules, now puts each workspace project's dependencies in <project>/www/modules on both fresh and frozen installs, and pnpm bin prints <project>/www/modules/.bin #​15484.

  • With nodeLinker: hoisted, pnpm now installs the root project's dependencies into a custom modulesDir instead of node_modules. With a custom modulesDir, the virtual store and its lock.yaml now default to <modulesDir>/.pnpm.

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

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

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

Adding, updating, and removing dependencies
  • 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 <pkg>@<version> and pnpm update <pkg>@<version> now move the catalog entry onto the named version when the entry's range already covers it. For example, ^7.22.17 becomes ^7.29.6, the same way pnpm update <pkg> moves an entry to the version it resolves #​13715.

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

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

  • pnpm install now prunes unreferenced catalog entries from pnpm-workspace.yaml when catalogPrune: true is configured #​15273.

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

  • Exclude entries that pnpm writes to pnpm-workspace.yaml now match the file's list indentation and dominant quote style #​15571, #​15079.

  • 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, pnpm patch-commit, and pnpm patch-remove now work in a project of a workspace with sharedWorkspaceLockfile: false. pnpm patch failed there with ERR_PNPM_PATCH_NO_LOCKFILE after a successful install. The reinstall after committing or removing a patch left the project's own node_modules unchanged #​9926.

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

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 in child environments when Node.js is available. Stale inherited NODE and npm_node_execpath variables are cleared when Node.js cannot be found on PATH #​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 and pnpm exec with verifyDepsBeforeRun now accept a moved project whose store is on the project's volume. Before, the check reported that the workspace structure had changed whenever the default store was not on the home volume.

  • verifyDepsBeforeRun checks now account for project-specific packageConfigs overrides in workspaces with sharedWorkspaceLockfile: false #​15545.

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

  • pnpm pipeline no longer fails when run in a project outside a Git work tree or on a system without git. Tasks in those projects run without caching, and pnpm prints a warning explaining why #​15601.

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

  • A script killed by a signal now fails with an error that names the signal, such as Command failed with signal SIGKILL. #​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 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 does not run the prepare scripts of the deployed project #​7282.

  • pnpm deploy --legacy no longer rewrites the source workspace's node_modules/.pnpm-workspace-state-v1.json to describe only the deployed project #​15352.

Manifests and configuration files
  • pnpm now reads and updates package.json5 project manifests. Manifest updates retain comments, and workspace discovery prefers package.json, then package.json5, then package.yaml #​15129. pnpm pack includes exactly one package.json in the archive when the project uses an alternative manifest format, even when .npmignore or files excludes the source file.

  • Git-hosted dependencies that use a package.yaml or package.json5 manifest now honor its files field #​7906.

  • 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 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 init now supports the --bare option. It creates a package.json file with only the required fields #​15538.

  • The reporter setting is now honored when it is configured in pnpm-workspace.yaml, the global configuration, or the PNPM_CONFIG_REPORTER environment variable. Configured reporter: silent makes silent output the default. An explicit --reporter takes precedence #​4879.

  • .npmrc and pnpm-workspace.yaml 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.

  • 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 parses the first setting in a .npmrc that starts with a UTF-8 byte order mark. Previously, the leading byte order mark caused the first line's key to be ignored #​15353.

  • pnpm now prints a warning when a .npmrc, auth.ini, or the file set by npmrcAuthFile exists but cannot be read. The settings in such a file were ignored without any message. A .npmrc that contains invalid UTF-8 is now read #​5065.

  • pnpm config set and pnpm config delete now preserve comments and repeated keys such as ca= in .npmrc #​14851.

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

  • Commands that do not use the store no longer create a temporary file in the project directory when they load their settings. These include pnpm view, pnpm config, pnpm root, pnpm bin, pnpm exec, pnpm run, the script shortcuts such as pnpm test, and the registry commands such as pnpm whoami, pnpm dist-tag, and pnpm search. pnpm exec, pnpm run, and the script shortcuts still create one in projects that declare configDependencies.

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 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 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 now installs pnpm under the package name pnpm too, so both commands leave the same shims in the global bin directory. After a self-update on Windows, PowerShell ran pnpm through pnpm.cmd and asked "Terminate batch job (Y/N)?" on Ctrl+C #​15567.

  • pnpm setup failed with Text file busy (os error 26) when $PNPM_HOME/bin already held pn, pnpx, or pnx as links to the running pnpm executable. It now replaces those files and completes #​15494.

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

  • When pnpm switches to the version a project pins, the minimumReleaseAge approvals for that version are now added to minimumReleaseAgeExclude in the project's pnpm-workspace.yaml. A project without that file gets one. Global commands leave the project's settings unchanged #​15396.

  • pnpm env remove now cleans up dangling Node.js executables and shims. 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
  • On Windows, pnpm clean and installs no longer fail immediately when another process uses a package in node_modules. pnpm waits up to a minute for an open file. It waits up to 5 seconds for a running program #​15081.

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

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

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

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

  • On Windows, the error for a node_modules directory that pnpm cannot move out of the way now names the directory and says that a file in it is probably in use by another process #​7505.

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 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 every license as Unknown and listed paths under node_modules/.pnpm that do not exist. It now reads each package from the directory where the hoisted linker placed it #​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 now takes the author, description, license, repository, and bugs fields from the workspace root package.json when the project does not declare them. A field the project declares is never taken from the root, even when it is blank or null #​14882.

  • pnpm store status no longer reports a package as modified when it has build or postinstall scripts, peer dependencies, or skipped optional dependencies #​15383. 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.

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 #​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.

  • Fatal peer dependency errors and their hints are now written to stderr #​5419.

  • 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 run and pnpm exec now print No projects matched the filters in "<workspace>" when --filter selects no project #​8408.

  • pnpm dedupe now counts each package reused from the store once in its progress output #​15303.

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

  • pnpm link now warns when linking a package that declares one or more peer dependencies, explaining that the linked dependency will not resolve peer dependencies from the target node_modules and suggesting the file: protocol instead.

  • pnpm import now warns when package.json lists projects in a "workspaces" array and there is no "pnpm-workspace.yaml". Without that file, the import writes a lockfile for the root project only #​5240.

  • 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

Configuration

📅 Schedule: (UTC)

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

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

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

👻 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 | Type | Update | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---|---|---| | [docker.io/haproxy](https://hub.docker.com/_/haproxy) ([source](https://github.com/docker-library/haproxy)) | Kustomization | patch | `3.4.5` → `3.4.6` | ![age](https://developer.mend.io/api/mc/badges/age/docker/docker.io%2fhaproxy/3.4.6?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/docker/docker.io%2fhaproxy/3.4.5/3.4.6?slim=true) | | [ghcr.io/immich-app/immich-machine-learning](https://github.com/immich-app/immich) | Kustomization | patch | `v3.2.2` → `v3.2.4` | ![age](https://developer.mend.io/api/mc/badges/age/docker/ghcr.io%2fimmich-app%2fimmich-machine-learning/v3.2.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/docker/ghcr.io%2fimmich-app%2fimmich-machine-learning/v3.2.2/v3.2.4?slim=true) | | [ghcr.io/immich-app/immich-server](https://github.com/immich-app/immich) | Kustomization | patch | `v3.2.2` → `v3.2.4` | ![age](https://developer.mend.io/api/mc/badges/age/docker/ghcr.io%2fimmich-app%2fimmich-server/v3.2.4?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/docker/ghcr.io%2fimmich-app%2fimmich-server/v3.2.2/v3.2.4?slim=true) | | [pnpm](https://github.com/pnpm/pnpm/tree/main/pnpm) ([source](https://github.com/pnpm/pnpm/tree/HEAD/pnpm/npm/pnpm)) | packageManager | minor | [`12.6.0` → `12.8.1`](https://renovatebot.com/diffs/npm/pnpm/12.6.0/12.8.1) | ![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/12.8.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/12.6.0/12.8.1?slim=true) | --- ### Release Notes <details> <summary>immich-app/immich (ghcr.io/immich-app/immich-machine-learning)</summary> ### [`v3.2.4`](https://github.com/immich-app/immich/releases/tag/v3.2.4) [Compare Source](https://github.com/immich-app/immich/compare/v3.2.2...v3.2.4) It's been a while since we last had to sacrifice a release. Let's hope v3.2.3 was a good sacrifice for v3.3, which is right around the corner! Just another small patch that primarily fixes the memory leak people have observed through a dependency update. <!-- Release notes generated using configuration in .github/release.yml at v3.2.4 --> ##### What's Changed ##### 🐛 Bug fixes - fix(mobile): sync status page goes blank when the counts query fails by [@&#8203;immich-push-o-matic](https://github.com/immich-push-o-matic)\[bot] in [#&#8203;31644](https://github.com/immich-app/immich/pull/31644) **Full Changelog**: <https://github.com/immich-app/immich/compare/v3.2.2...v3.2.4> </details> <details> <summary>pnpm/pnpm (pnpm)</summary> ### [`v12.8.1`](https://github.com/pnpm/pnpm/releases/tag/v12.8.1): pnpm 12.8.1 [Compare Source](https://github.com/pnpm/pnpm/compare/pnpm@12.8.0...v12.8.1) pnpm 12.8.1 fixes `pnpm install --frozen-lockfile` rejecting lockfiles with injected workspace packages that have peers, restores the executable bit on files of local directory dependencies, makes `pnpm dedupe` converge, and uses less CPU on many-core machines. ##### Patch Changes - `pnpm install --frozen-lockfile` no longer rejects a freshly generated lockfile when an injected workspace package has peer dependencies [#&#8203;16332](https://github.com/pnpm/pnpm/issues/16332). - Executable files in a `file:` directory dependency or an injected workspace package keep their executable bit again. Since 12.8.0, pnpm installed these files without the permissions they have in their project. - `pnpm dedupe` now reaches a stable lockfile when a package's peer suffix is long enough to be hashed. Before, each run could switch that package's key between the hashed and the spelled-out suffix, so `pnpm dedupe --check` always failed [#&#8203;16331](https://github.com/pnpm/pnpm/issues/16331). - `pnpm install --frozen-lockfile`, the default in CI, now uses less CPU on machines with more than 8 cores. Warm installs on many-core Windows machines got up to 10% faster. Frozen installs now link with at most 16 worker threads. - `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). - `pnpm update -g --latest` now upgrades globally installed packages beyond their saved version ranges [#&#8203;16320](https://github.com/pnpm/pnpm/issues/16320). <!-- 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 --> ### [`v12.8.0`](https://github.com/pnpm/pnpm/releases/tag/v12.8.0): pnpm 12.8 [Compare Source](https://github.com/pnpm/pnpm/compare/v12.7.0...pnpm@12.8.0) pnpm 12.8.0 warns when `pnpm pack` or `pnpm publish` would ship a `.env` file that `files` does not list, installs `sharedWorkspaceLockfile: false` workspaces concurrently, applies every setting passed as `--config.<name>=<value>`, and no longer leaves the Windows terminal stuck after Ctrl+C in a script. ##### Minor Changes - `pnpm pack` and `pnpm publish` now warn when the tarball includes a `.env` or `.env.*` file that the `files` field of `package.json` does not list. Templates such as `.env.example` are not reported. List the file in `files` to publish it on purpose, or exclude it in `.npmignore` or `.gitignore` [#&#8203;7826](https://github.com/pnpm/pnpm/issues/7826). - `pnpm pack` now honors `--silent`, `--reporter=silent`, and `--loglevel=silent` to hide the tarball contents and summary. With `--json`, lifecycle script output and the final JSON output remain visible [#&#8203;10297](https://github.com/pnpm/pnpm/issues/10297). ##### Patch Changes ##### Installing packages - Installing through a `pnpr` server now records the pnpmfile checksum in the lockfile, so a later `pnpm install --frozen-lockfile` accepts that lockfile [#&#8203;14460](https://github.com/pnpm/pnpm/issues/14460). 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. Installing through a `pnpr` server also links a workspace project at the directory its `publishConfig.directory` names. A server that does not forward the setting makes the install fail with `ERR_PNPM_PNPR_PUBLISH_DIRECTORY_MISMATCH`, so pnpm never writes a lockfile that points at the wrong directory. The server rejects a `publishConfig.directory` that points outside its project. - 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). - A git-hosted dependency that is a pnpm workspace with no committed lockfile is now detected as a pnpm project [#&#8203;14011](https://github.com/pnpm/pnpm/issues/14011). - `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 --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. The error also carries the `ERR_PNPM_NO_OFFLINE_META` code. `pnpm cache prune --help` now says that pnpm 11.26 and earlier, and pnpm 12.3 and earlier, depend on the directories it removes [#&#8203;15656](https://github.com/pnpm/pnpm/issues/15656). - Running `pnpm install` now refreshes dependencies when a package declared with a local `file:` directory changes its dependencies [#&#8203;4623](https://github.com/pnpm/pnpm/issues/4623). - A repeat `pnpm install` now keeps its fast up-to-date check when an override replaces a declared local `file:` dependency [#&#8203;12892](https://github.com/pnpm/pnpm/issues/12892). - `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). - 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. On Windows, the install also no longer fails with "Access is denied" when another project's copy of a shared dependency links to the deleted directory. - 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). - 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 write. ##### Resolving and linking dependencies - `pnpm install` no longer aborts on a failed allocation of many gigabytes when peer dependency ranges combine overlapping `||` alternatives [#&#8203;15867](https://github.com/pnpm/pnpm/issues/15867). - `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). - An `npm:` alias written by `overrides` now stays in place when a change elsewhere makes pnpm re-resolve the aliased dependency. Before, pnpm could look up the alias name at the aliased version, which failed with `ERR_PNPM_NO_MATCHING_VERSION` or locked an unrelated package [#&#8203;16309](https://github.com/pnpm/pnpm/issues/16309). - 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 dedupe` no longer changes the lockfile on every run when a nested peer dependency is provided through an npm alias [#&#8203;15709](https://github.com/pnpm/pnpm/issues/15709). - 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). - `pnpm install` retries registry metadata fetches that fail with a timeout, a dropped connection, or an interrupted response body before it applies `trustPolicy` or `minimumReleaseAge`. A transient fetch failure is not reported as `TRUST_DOWNGRADE` or `MINIMUM_RELEASE_AGE_VIOLATION` [#&#8203;12031](https://github.com/pnpm/pnpm/issues/12031). - 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). - 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). - `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). ##### Lockfiles and frozen installs - `pnpm install --frozen-lockfile` now works on a detached HEAD when `gitBranchLockfile` is enabled. The install 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 --frozen-lockfile` now accepts a lockfile that has no importer entry for a workspace package without dependencies. Such a package added after the lockfile was written made the install fail with `ERR_PNPM_PACKAGE_MANAGER_NO_IMPORTER` [#&#8203;15875](https://github.com/pnpm/pnpm/issues/15875). - `pnpm install` now fails with `ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY` when an importer references a dependency version that has no snapshot entry. Before, the install succeeded and left a `node_modules` symlink pointing at a missing virtual-store directory [#&#8203;14764](https://github.com/pnpm/pnpm/issues/14764). - `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). - With `gitBranchLockfile` enabled, each emoji or other character outside the Basic Multilingual Plane in a branch name now becomes `!!` in the lockfile name. Before, each such character became one `!`. ##### Workspaces and filtering - `pnpm install` in a workspace with `sharedWorkspaceLockfile: false` now installs projects concurrently, up to `workspaceConcurrency` at a time [#&#8203;14480](https://github.com/pnpm/pnpm/issues/14480). A project is resolved, fetched, and written to its virtual store without waiting for the workspace projects it depends on. It waits for them only before it links its dependencies and runs its lifecycle scripts, so its scripts still run after theirs. A project with a `preinstall` or `pnpm:devPreinstall` script, or with an injected or `file:` workspace dependency, waits for its workspace dependencies before it starts. The installs of the projects also share their package metadata, lockfile verification, and store caches, so they use less CPU and memory when several projects depend on the same packages. An install with a pnpmfile no longer starts an extra Node.js process when the pnpmfile has no `preResolution` hook. - With `enableGlobalVirtualStore` and `sharedWorkspaceLockfile: false`, each project now keeps its current lockfile and its hidden hoisted dependencies in its own `node_modules/.pnpm`. Before, every project wrote them to the workspace root's `node_modules/.pnpm`, so each repeat install treated the other projects' packages as its own and relinked them [#&#8203;14480](https://github.com/pnpm/pnpm/issues/14480). - `pnpm rebuild`, `pnpm approve-builds`, and `pnpm ignored-builds` now work on the current project's `node_modules` when they run inside a project of a workspace with `sharedWorkspaceLockfile: false`. They used to read the workspace root's `node_modules`, so `pnpm rebuild` did not rebuild the project's dependencies and created a second virtual store at the workspace root [#&#8203;9402](https://github.com/pnpm/pnpm/issues/9402). - `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). It also no longer fails with `ERR_PNPM_CMD_SHIM_RESOLVE_PATH` when such a package has a `bin` field and its `publishConfig.directory` does not exist yet. - `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). - An in-place edit to the source of an injected workspace package now shows up in its injected copy, unless a build writes to that package or `packageImportMethod` is set. pnpm hardlinks such packages under the default import method [#&#8203;4410](https://github.com/pnpm/pnpm/issues/4410). Scripts listed in `syncInjectedDepsAfterScripts` now update injected dependencies while they run, so a watcher on the injected package, such as a dev server, sees each change before the script exits. - 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). - Workspace discovery prunes dot-prefixed directories, so a `packages` pattern such as `**` no longer matches projects inside `.cache` and other hidden directories [#&#8203;16250](https://github.com/pnpm/pnpm/issues/16250). - `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). ##### Store and caches - 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). - `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, so hard-linked copies in other projects are healed at the same time. 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). - `pnpm install` now reports a full store at once when writing package files fails. It no longer retries the tarball [#&#8203;8581](https://github.com/pnpm/pnpm/issues/8581). - pnpm now warns when it cannot hard link packages from an existing store in the pnpm home directory and falls back to 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). - 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. - 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. - With `enableGlobalVirtualStore`, an install into a fresh `node_modules` no longer runs the build scripts of a dependency whose global virtual store slot an earlier install already built. `pnpm rebuild` still runs them [#&#8203;14480](https://github.com/pnpm/pnpm/issues/14480). - 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). - 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). - 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 install` honors `Cache-Control` for dependencies named with an `http:` or `https:` tarball URL. A fresh response is taken from the store with no request, and a stale one is revalidated with `If-None-Match` [#&#8203;15648](https://github.com/pnpm/pnpm/issues/15648). ##### 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. Before, pnpm 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` with `nodeLinker: hoisted` now applies a patch once to each copy of a patched dependency in a workspace. Before, a copy that several workspace projects shared could receive the patch twice and end up with the patched content duplicated [#&#8203;7565](https://github.com/pnpm/pnpm/issues/7565). - `pnpm install` and `pnpm fetch` now fail with `ERR_PNPM_PATCH_NOT_FOUND` when a patch file listed in `patchedDependencies` does not exist [#&#8203;5268](https://github.com/pnpm/pnpm/issues/5268). - `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). ##### Adding, updating, and removing dependencies - `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). - `pnpm add --save-types` no longer adds a `@types/*` package whose resolved version is deprecated. DefinitelyTyped publishes such stubs for packages that ship their own types, such as `@types/typescript` for `typescript` [#&#8203;15636](https://github.com/pnpm/pnpm/issues/15636). - `pnpm version`, `pnpm add`, and `pnpm pkg set` keep JSON5 style when they update `package.json5`. ASCII identifier keys stay unquoted, strings keep JSON5 quotes, and indented files keep trailing commas [#&#8203;15717](https://github.com/pnpm/pnpm/issues/15717). ##### 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). - 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 -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). - `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 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). - `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). - With `enableGlobalVirtualStore`, dependency build scripts now see the workspace root's `node_modules/.bin`, as they do with a local virtual store. A `postinstall` script that runs `node` finds the Node.js installed by `devEngines.runtime` and no longer fails with "command not found" on machines without a system Node.js [#&#8203;15652](https://github.com/pnpm/pnpm/issues/15652). Dependency build scripts also see the bins of privately hoisted dependencies. - Dependency install scripts now find the node-gyp bundled with pnpm when pnpm runs through a symlink, such as `node_modules/.bin/pnpm` or the `pnpm` that `npm install -g pnpm` links. They used to fail with `node-gyp: command not found` on macOS [#&#8203;15694](https://github.com/pnpm/pnpm/issues/15694). - `pnpm run` and lifecycle scripts now set `npm_config_node_gyp` to the bundled `node-gyp` entry point. Tools that read the variable resolve the same `node-gyp` pnpm builds with. An `npm_config_node_gyp` value the environment already sets is kept as is [#&#8203;16270](https://github.com/pnpm/pnpm/issues/16270). - Scripts now see the `npm_command` environment variable that npm sets. It holds `run-script` when the command runs a script, and the command's own name otherwise [#&#8203;16265](https://github.com/pnpm/pnpm/issues/16265). - 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). - `pnpx --version` and `pnpm dlx --version` now print the pnpm version. Other unknown options before the command are reported as errors. Before, pnpm tried to download a package named after the option [#&#8203;16259](https://github.com/pnpm/pnpm/issues/16259). - `pnpm dlx` now keeps the virtual store of its cached installs in `node_modules/.pnpm`, like every other install [#&#8203;13955](https://github.com/pnpm/pnpm/issues/13955). `pnpm pack-app` now names the manifest of its runtime install directory `pnpm-pack-app-<target>`. ##### Publishing, packing, and deploying - `pnpm pack` and `pnpm publish` now ship a file that the `files` field names even when another entry excludes the directory holding it. For example, `["**", "!dist", "dist/index.d.ts"]` ships `dist/index.d.ts` [#&#8203;16213](https://github.com/pnpm/pnpm/issues/16213). - `pnpm pack` prunes a directory that a `files` field exclusion names, such as `!**/test`, excluding the directory and its contents from the packed package [#&#8203;15738](https://github.com/pnpm/pnpm/issues/15738). - `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 --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` with a shared lockfile now copies workspace dependencies into the deploy directory, even when `packageImportMethod` is set to `hardlink`. Before, 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 --legacy` no longer leaves broken links to nested local dependencies of workspace packages [#&#8203;9575](https://github.com/pnpm/pnpm/issues/9575). ##### Configuration and pnpmfile hooks - Every setting pnpm supports can now be set with `--config.<name>=<value>` on the command line, not only the ones whose command also carries a matching flag. Before, `pnpm install --config.frozen-lockfile=true` dropped the setting and rewrote `pnpm-lock.yaml` as though the install had not been frozen [#&#8203;16276](https://github.com/pnpm/pnpm/issues/16276). - 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). - `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). - pnpm now fails with `ERR_PNPM_AUTH_INVALID_BASE64` when a registry's `_password` in `.npmrc` is not valid base64. Before, it sent the value as the raw password. A `username` or `_password` left empty, for example by an unset environment variable, now supplies no credential [#&#8203;16273](https://github.com/pnpm/pnpm/issues/16273). - `proxy=false` now turns proxying off even when `HTTP_PROXY`, `HTTPS_PROXY`, or `ALL_PROXY` is set. pnpm no longer sends requests through a proxy named only in `ALL_PROXY`. - `pnpm install` now runs the install hooks of a config dependency plugin's pnpmfile, including `readPackage`, `afterAllResolved`, and custom resolvers. Its pnpmfile is also counted in `pnpmfileChecksum`. Before, only the plugin's `updateConfig` hook ran, so a plugin could not change the resolved dependencies. - A pnpmfile `fetchers` hook now runs once per package on a fresh install when it handles a resolution with a custom `type` or delegates a git-hosted one to the same subdirectory [#&#8203;15584](https://github.com/pnpm/pnpm/issues/15584). These packages were fetched a second time for installation, so the installed files could come from a different archive than the one their dependencies were read from. The hook also no longer runs twice when a `resolvers` hook returns a tarball resolution without a manifest [#&#8203;15025](https://github.com/pnpm/pnpm/issues/15025). - `pnpm install` now re-fetches a package from a custom resolver when the `integrity` of its resolution changes, with or without `enableGlobalVirtualStore`. It used to update the lockfile but keep the old files in `node_modules` [#&#8203;15670](https://github.com/pnpm/pnpm/issues/15670). - `pnpm install` now rejects invalid results from a `readPackage` hook. A hook that returns a non-object value fails with `ERR_PNPM_BAD_READ_PACKAGE_HOOK_RESULT` [#&#8203;15730](https://github.com/pnpm/pnpm/issues/15730). A hook that sets a dependency range to a value other than a string, such as `undefined`, fails with an error that names the dependency, the package and the pnpmfile. Delete the property to remove a dependency [#&#8203;15705](https://github.com/pnpm/pnpm/issues/15705). ##### 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). - 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). - On arm64 musl Linux, such as Alpine on ARM, switching to a pinned pnpm older than 12 now runs the JavaScript `pnpm` package. The standalone executable of those versions crashed at startup on that platform [#&#8203;10443](https://github.com/pnpm/pnpm/issues/10443). - Global shims such as `node` now work when pnpm runs through a relative symlink, as with a Homebrew install. They were copies of that symlink and did not resolve from the global bin directory [#&#8203;15691](https://github.com/pnpm/pnpm/issues/15691). - `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). ##### Windows - Interrupting a script with Ctrl+C on Windows no longer leaves the terminal stuck [#&#8203;14860](https://github.com/pnpm/pnpm/issues/14860). A script that runs through a batch shim, as `vite dev` does through `vite.CMD`, made cmd.exe wait forever on its "Terminate batch job (Y/N)?" answer, and every following keystroke went to that prompt. pnpm now ends a cmd.exe script shell once it has sat for a second after the interrupt with nothing running under it. A script that takes longer to shut down is still waited for. A second Ctrl+C ends the script's shell at once. - 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). - The Windows `pnpm.exe` runs on a clean Windows install that does not have the Visual C++ Redistributable. It used to exit immediately on startup because that runtime was missing [#&#8203;15723](https://github.com/pnpm/pnpm/issues/15723). - 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). Command shims also run tools whose paths contain non-ASCII characters [#&#8203;6999](https://github.com/pnpm/pnpm/issues/6999), including the PowerShell shims in Windows PowerShell 5.1 [#&#8203;16217](https://github.com/pnpm/pnpm/issues/16217). - 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). - On Windows, installing pnpm with npm inside a project now writes `node_modules/.bin` shims that run `pnpm.exe`. A global install with `npm install --location=global` now gets the same shims as `npm install -g` [#&#8203;15688](https://github.com/pnpm/pnpm/issues/15688). - `pnpm install` no longer fails with `ERR_PNPM_WORKSPACE_INVALID_GLOB` on Windows for a wildcard pattern such as `plugins/*/*` in `pnpm-workspace.yaml` when the workspace is on a different drive than the pnpm cache or state directory [#&#8203;16239](https://github.com/pnpm/pnpm/issues/16239). - On Windows, `pnpm install` no longer skips a dependency's build script on a later install when the package ships an executable file and the script changes nothing inside the package directory [#&#8203;15667](https://github.com/pnpm/pnpm/issues/15667). - `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). - `pnpm setup` on Windows no longer panics when an unrelated environment variable has a name containing a non-ASCII character. It skips that variable [#&#8203;15684](https://github.com/pnpm/pnpm/issues/15684). - 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. Before, it showed the directory pnpm wanted to set. - 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). ##### Inspecting dependencies - `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). - `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). With `--json`, its `paths` array now includes every installed copy of a package, including hoisted copies and isolated installations with different peer dependencies. - `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). ##### 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. - When a dependency fails to resolve, the error now shows the cause. For example, a Node.js runtime download behind a proxy that re-signs TLS now reports `invalid peer certificate: UnknownIssuer` [#&#8203;9556](https://github.com/pnpm/pnpm/issues/9556). - 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). - Lockfile verification now fails with `ERR_PNPM_TARBALL_URL_MISMATCH`, `ERR_PNPM_TARBALL_REVISION_MISMATCH`, or `ERR_PNPM_MISSING_NAMED_REGISTRY` when every rejected entry failed that check. These failures were reported as the generic `ERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATION`. - 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 install` no longer prints an extra `Progress:` line after the progress line is marked `done` [#&#8203;16184](https://github.com/pnpm/pnpm/issues/16184). <!-- 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 --> ### [`v12.7.0`](https://github.com/pnpm/pnpm/releases/tag/v12.7.0): pnpm 12.7 [Compare Source](https://github.com/pnpm/pnpm/compare/v12.6.0...v12.7.0) pnpm 12.7.0 ships with `.nvmrc` and `.node-version` support in the global `node` shim, `pnpm install --allow-build`, `pnpm publish --publish-wait-timeout`, and `pnpm-workspace.yaml` created from the `workspaces` field. `pnpm install --force` no longer installs optional dependencies built for other platforms. This release also carries security fixes for bin shims on Nix, for lifecycle scripts of packages in a `storeDir` inside the workspace, and for `userAgent` placeholders in `pnpm-workspace.yaml`. ##### Minor Changes - `pnpm install --force` now keeps skipping optional dependencies whose `os`, `cpu` or `libc` do not match the host. It still refetches every package and lifts `engineStrict`. The new `forceIgnoresPlatform` setting restores the previous behaviour, installing optional dependencies of every platform under `--force` [#&#8203;6133](https://github.com/pnpm/pnpm/issues/6133). - The global `node` shim created by pnpm now uses the Node.js version from the nearest `.nvmrc` or `.node-version` file when the project does not declare a Node.js runtime in `devEngines.runtime` or `engines.runtime` [#&#8203;4471](https://github.com/pnpm/pnpm/issues/4471). The nearest directory with a Node.js runtime declaration decides the version. Within one directory, `package.json` takes precedence over `.node-version`, which takes precedence over `.nvmrc`. An `.nvmrc` value that only nvm can act on, such as `system` or a custom alias, is ignored. - `pnpm install` now supports the `--allow-build` option to selectively allow or deny package lifecycle scripts and record them in `pnpm-workspace.yaml` [#&#8203;15388](https://github.com/pnpm/pnpm/issues/15388). - Added `pnpm publish --publish-wait-timeout <milliseconds>` to wait for published versions and their tarballs to become available from the registry. Set `publishWaitTimeout` in `pnpm-workspace.yaml` to configure a default. A value of `0` disables the check. Recursive publishing confirms availability before publishing dependent packages. If confirmation times out, the command fails. When `pnpm publish -r --report-summary` fails after some uploads were accepted, the summary file now lists those packages. - `pnpm install` now creates `pnpm-workspace.yaml` from the `workspaces` field of the root `package.json` when the repository has no `pnpm-workspace.yaml`. The projects the field lists are linked on that same install. An existing `pnpm-workspace.yaml` is never changed. With `--ignore-workspace`, no file is created. If the `workspaces` field later differs from `packages` in `pnpm-workspace.yaml`, pnpm prints a warning [#&#8203;2255](https://github.com/pnpm/pnpm/issues/2255). - When a project pins a pnpm version or a runtime that another pnpm process is installing at that moment, pnpm now waits a few seconds and then installs and runs a private copy of its own. It used to wait up to five minutes and then use the shared install directory without the lock. The private copy is removed once the command has run. `pnpm store prune` removes any private copy that a killed process left behind [#&#8203;15413](https://github.com/pnpm/pnpm/issues/15413). - pnpm now keeps the blank lines between entries of `package.json` when it updates the file, for example on `pnpm add` [#&#8203;5602](https://github.com/pnpm/pnpm/issues/5602). ##### 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). - 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). - pnpm no longer treats manifests inside its store, cache, state, or modules directories as workspace projects. Before, a `storeDir` inside the workspace could let lifecycle scripts of packages in the store run without `allowBuilds` approval [#&#8203;15033](https://github.com/pnpm/pnpm/issues/15033). - Packages that run a lifecycle script are no longer hard-linked into the virtual store, so a build script can no longer rewrite the workspace source of an injected package or the store copy it was imported from [#&#8203;15483](https://github.com/pnpm/pnpm/issues/15483). ##### Installing packages - Fixed `pnpm install`, `pnpm add`, `pnpm remove`, and `pnpm peers check` running out of memory when many packages share a missing peer dependency. This mostly affected projects with `autoInstallPeers: false` [#&#8203;15362](https://github.com/pnpm/pnpm/issues/15362). - pnpm no longer hangs for up to 5 minutes after a pnpm process was killed while setting up the pnpm version pinned in `packageManager` or `devEngines` [#&#8203;15360](https://github.com/pnpm/pnpm/issues/15360), [#&#8203;15393](https://github.com/pnpm/pnpm/issues/15393). The killed process left behind a lock that every later pnpm command in the project waited on. pnpm now detects that the process holding a lock is gone and takes the lock over at once. The same applies to the locks pnpm takes while installing a managed runtime or writing the global bin directory. Two pnpm processes that are both still running keep waiting for each other as before. - Requests to a registry or tarball server whose TLS certificate fails verification now fail at once. Such requests were retried for more than a minute without any output [#&#8203;9134](https://github.com/pnpm/pnpm/issues/9134). - On macOS, pnpm now falls back to its bundled CA roots when system trust evaluation is unavailable, such as in a sandbox or when macOS cannot create an SSL policy for a registry connection. Installs failed or crashed on the first registry request in that case. Custom `ca` certificates are now honored directly [#&#8203;15329](https://github.com/pnpm/pnpm/issues/15329), [#&#8203;14461](https://github.com/pnpm/pnpm/issues/14461). - `pnpm install` now caps concurrent connections to a proxy at 50 sockets by default [#&#8203;15280](https://github.com/pnpm/pnpm/issues/15280). It also immediately retries transient connection resets when downloading package archives. - `pnpm install` now reuses a package already present in the store when an existing lockfile entry satisfies the dependency, avoiding registry requests that fail without authorization [#&#8203;2522](https://github.com/pnpm/pnpm/issues/2522). - 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 installs the new version of a local tarball dependency whose file was replaced at the same path [#&#8203;2437](https://github.com/pnpm/pnpm/issues/2437). `pnpm install --frozen-lockfile` rejects such a changed tarball, even when the previous archive contents are in the store [#&#8203;1889](https://github.com/pnpm/pnpm/issues/1889). - `pnpm install` now fetches committed submodules of git dependencies [#&#8203;1470](https://github.com/pnpm/pnpm/issues/1470). - `pnpm install` now applies patches produced by `pnpm patch-commit` when an edit removes the trailing lines of a file along with its newline. The install no longer fails with `ERR_PNPM_INVALID_PATCH` ("expected end of hunk") [#&#8203;12451](https://github.com/pnpm/pnpm/issues/12451). - `pnpm install` now preserves existing `node_modules` directories when a cross-device move reports `EXDEV` [#&#8203;14504](https://github.com/pnpm/pnpm/issues/14504). - `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). - 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` 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` uses less CPU when it links packages from a warm store. On Windows, a warm install could take several times longer than with pnpm 11 [#&#8203;15439](https://github.com/pnpm/pnpm/issues/15439). - `pnpm install` now runs `node --version` once per run. A workspace whose projects keep their own lockfiles (`sharedWorkspaceLockfile: false`) previously ran the probe once or twice for every project, and on macOS the concurrent launches waited on each other, so a project could wait several seconds before its linking started. - A repeat `pnpm install --frozen-lockfile` with `nodeLinker: hoisted` in a workspace no longer re-links `node_modules` when nothing changed. - Custom fetcher hooks no longer run a second time during installation when an archive was already fetched during dependency resolution [#&#8203;15025](https://github.com/pnpm/pnpm/issues/15025). - Fixed a package resolved by a `resolvers` pnpmfile hook installing without its own dependencies. This happened when the hook returned no `manifest` and a `fetchers` hook handled the resolution [#&#8203;15552](https://github.com/pnpm/pnpm/issues/15552). - `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 do installs given package arguments. - `pnpm prune --prod` and production installs now remove devDependencies when `lockfile: false` is configured [#&#8203;2677](https://github.com/pnpm/pnpm/issues/2677). - `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 install` no longer skips optional dependencies that the Node.js version locked 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 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). - pnpm now detects the same CI environments as pnpm 11, including AWS CodeBuild, which does not set `CI`. On these services `pnpm install` uses a frozen lockfile by default and fails with `ERR_PNPM_OUTDATED_LOCKFILE` when the lockfile is outdated. ##### Resolving and linking dependencies - 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). - 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` now re-resolves a dependency when its manifest range is updated from a prerelease to a stable version. The lockfile previously retained the prerelease version and caused `--frozen-lockfile` to fail [#&#8203;15528](https://github.com/pnpm/pnpm/issues/15528). - `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` and `pnpm peers check` now use local tarball packages' actual versions when checking peer dependencies. Compatible packages no longer fail with `strictPeerDependencies` enabled. - `pnpm peers check` and the install-time peer dependency check now resolve peer dependencies from the workspace root when `resolvePeersFromWorkspaceRoot` is enabled [#&#8203;14982](https://github.com/pnpm/pnpm/issues/14982). - `autoDedupe` and `pnpm dedupe` now move transitive dependencies to the version a `catalog:` dependency pins, as they already did for versions written directly in `package.json`. Previously they could move those dependencies to a higher version and keep both versions in the lockfile. - `pnpm dedupe` now produces a stable lockfile when a dependency's range matches both a direct dependency and an `npm:` alias of the same package. The dependency resolves to the version of the direct dependency. Repeated runs previously alternated between two lockfiles [#&#8203;15588](https://github.com/pnpm/pnpm/issues/15588). - 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). - Tarball URLs recorded in the lockfile now strip default HTTP and HTTPS ports (`:80` and `:443`) [#&#8203;15539](https://github.com/pnpm/pnpm/issues/15539). - `node_modules/.package-map.json` no longer contains entries that point at directories that do not exist. Such entries appeared for packages installed only with peer dependencies, most visibly with `enableGlobalVirtualStore` [#&#8203;14938](https://github.com/pnpm/pnpm/issues/14938). - 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). - 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` no longer puts a dependency's bin on `PATH` for that dependency's own lifecycle scripts before the bin's file exists. pnpm links such a bin after the dependency's build has run. It also removes such a bin left by an earlier install. This fixes installing the `node` package on Windows [#&#8203;15501](https://github.com/pnpm/pnpm/issues/15501). - 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). - Bin linking leaves workspace and linked dependency files outside node\_modules unchanged. Already executable bin files no longer receive redundant permission changes. ##### Workspaces and filtering - `pnpm install` now finds workspace projects reached through a symlink, such as a `packages` directory that links to a folder outside the workspace. It 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). - 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 -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). - `pnpm install` now copies the output of a workspace package's own `prepare`, `install`, or `postinstall` script into the injected copies of that package. Before, the injected copies kept only the files that existed before the script ran. `syncInjectedDepsAfterScripts` now also works when `modulesDir` is set [#&#8203;9464](https://github.com/pnpm/pnpm/issues/9464). - `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). - A `modulesDir` with several path segments, such as `www/modules`, now puts each workspace project's dependencies in `<project>/www/modules` on both fresh and frozen installs, and `pnpm bin` prints `<project>/www/modules/.bin` [#&#8203;15484](https://github.com/pnpm/pnpm/issues/15484). - With `nodeLinker: hoisted`, pnpm now installs the root project's dependencies into a custom `modulesDir` instead of `node_modules`. With a custom `modulesDir`, the virtual store and its `lock.yaml` now default to `<modulesDir>/.pnpm`. - 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. - 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). - 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). ##### Adding, updating, and removing dependencies - `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 <pkg>@<version>` and `pnpm update <pkg>@<version>` now move the catalog entry onto the named version when the entry's range already covers it. For example, `^7.22.17` becomes `^7.29.6`, the same way `pnpm update <pkg>` moves an entry to the version it resolves [#&#8203;13715](https://github.com/pnpm/pnpm/issues/13715). - `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). - `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 <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 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). - `pnpm install` now prunes unreferenced catalog entries from `pnpm-workspace.yaml` when `catalogPrune: true` is configured [#&#8203;15273](https://github.com/pnpm/pnpm/issues/15273). - `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). - Exclude entries that pnpm writes to `pnpm-workspace.yaml` now match the file's list indentation and dominant quote style [#&#8203;15571](https://github.com/pnpm/pnpm/issues/15571), [#&#8203;15079](https://github.com/pnpm/pnpm/issues/15079). - `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`, `pnpm patch-commit`, and `pnpm patch-remove` now work in a project of a workspace with `sharedWorkspaceLockfile: false`. `pnpm patch` failed there with `ERR_PNPM_PATCH_NO_LOCKFILE` after a successful install. The reinstall after committing or removing a patch left the project's own `node_modules` unchanged [#&#8203;9926](https://github.com/pnpm/pnpm/issues/9926). - `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. ##### 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` in child environments when Node.js is available. Stale inherited `NODE` and `npm_node_execpath` variables are cleared when Node.js cannot be found on PATH [#&#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` and `pnpm exec` with `verifyDepsBeforeRun` now accept a moved project whose store is on the project's volume. Before, the check reported that the workspace structure had changed whenever the default store was not on the home volume. - `verifyDepsBeforeRun` checks now account for project-specific `packageConfigs` overrides in workspaces with `sharedWorkspaceLockfile: false` [#&#8203;15545](https://github.com/pnpm/pnpm/issues/15545). - `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 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). - `pnpm pipeline` no longer fails when run in a project outside a Git work tree or on a system without `git`. Tasks in those projects run without caching, and pnpm prints a warning explaining why [#&#8203;15601](https://github.com/pnpm/pnpm/issues/15601). - 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). - A script killed by a signal now fails with an error that names the signal, such as `Command failed with signal SIGKILL.` [#&#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 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` does not run the `prepare` scripts of the deployed project [#&#8203;7282](https://github.com/pnpm/pnpm/issues/7282). - `pnpm deploy --legacy` no longer rewrites the source workspace's `node_modules/.pnpm-workspace-state-v1.json` to describe only the deployed project [#&#8203;15352](https://github.com/pnpm/pnpm/issues/15352). ##### Manifests and configuration files - pnpm now reads and updates `package.json5` project manifests. Manifest updates retain comments, and workspace discovery prefers `package.json`, then `package.json5`, then `package.yaml` [#&#8203;15129](https://github.com/pnpm/pnpm/issues/15129). `pnpm pack` includes exactly one `package.json` in the archive when the project uses an alternative manifest format, even when `.npmignore` or `files` excludes the source file. - Git-hosted dependencies that use a `package.yaml` or `package.json5` manifest now honor its `files` field [#&#8203;7906](https://github.com/pnpm/pnpm/issues/7906). - 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 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 init` now supports the `--bare` option. It creates a `package.json` file with only the required fields [#&#8203;15538](https://github.com/pnpm/pnpm/issues/15538). - The `reporter` setting is now honored when it is configured in `pnpm-workspace.yaml`, the global configuration, or the `PNPM_CONFIG_REPORTER` environment variable. Configured `reporter: silent` makes silent output the default. An explicit `--reporter` takes precedence [#&#8203;4879](https://github.com/pnpm/pnpm/issues/4879). - `.npmrc` and `pnpm-workspace.yaml` 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`. - 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 parses the first setting in a `.npmrc` that starts with a UTF-8 byte order mark. Previously, the leading byte order mark caused the first line's key to be ignored [#&#8203;15353](https://github.com/pnpm/pnpm/issues/15353). - pnpm now prints a warning when a `.npmrc`, `auth.ini`, or the file set by `npmrcAuthFile` exists but cannot be read. The settings in such a file were ignored without any message. A `.npmrc` that contains invalid UTF-8 is now read [#&#8203;5065](https://github.com/pnpm/pnpm/issues/5065). - `pnpm config set` and `pnpm config delete` now preserve comments and repeated keys such as `ca=` in `.npmrc` [#&#8203;14851](https://github.com/pnpm/pnpm/issues/14851). - `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). - Commands that do not use the store no longer create a temporary file in the project directory when they load their settings. These include `pnpm view`, `pnpm config`, `pnpm root`, `pnpm bin`, `pnpm exec`, `pnpm run`, the script shortcuts such as `pnpm test`, and the registry commands such as `pnpm whoami`, `pnpm dist-tag`, and `pnpm search`. `pnpm exec`, `pnpm run`, and the script shortcuts still create one in projects that declare `configDependencies`. ##### 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` 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 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` now installs pnpm under the package name `pnpm` too, so both commands leave the same shims in the global bin directory. After a self-update on Windows, PowerShell ran pnpm through `pnpm.cmd` and asked "Terminate batch job (Y/N)?" on Ctrl+C [#&#8203;15567](https://github.com/pnpm/pnpm/issues/15567). - `pnpm setup` failed with `Text file busy (os error 26)` when `$PNPM_HOME/bin` already held `pn`, `pnpx`, or `pnx` as links to the running pnpm executable. It now replaces those files and completes [#&#8203;15494](https://github.com/pnpm/pnpm/issues/15494). - `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). - When pnpm switches to the version a project pins, the `minimumReleaseAge` approvals for that version are now added to `minimumReleaseAgeExclude` in the project's `pnpm-workspace.yaml`. A project without that file gets one. Global commands leave the project's settings unchanged [#&#8203;15396](https://github.com/pnpm/pnpm/issues/15396). - `pnpm env remove` now cleans up dangling Node.js executables and shims. 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 - On Windows, `pnpm clean` and installs no longer fail immediately when another process uses a package in `node_modules`. pnpm waits up to a minute for an open file. It waits up to 5 seconds for a running program [#&#8203;15081](https://github.com/pnpm/pnpm/issues/15081). - `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). - 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). - 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). - 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). - On Windows, the error for a `node_modules` directory that pnpm cannot move out of the way now names the directory and says that a file in it is probably in use by another process [#&#8203;7505](https://github.com/pnpm/pnpm/issues/7505). ##### 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` 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 every license as `Unknown` and listed paths under `node_modules/.pnpm` that do not exist. It now reads each package from the directory where the hoisted linker placed it [#&#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 now takes the `author`, `description`, `license`, `repository`, and `bugs` fields from the workspace root `package.json` when the project does not declare them. A field the project declares is never taken from the root, even when it is blank or `null` [#&#8203;14882](https://github.com/pnpm/pnpm/issues/14882). - `pnpm store status` no longer reports a package as modified when it has build or postinstall scripts, peer dependencies, or skipped optional dependencies [#&#8203;15383](https://github.com/pnpm/pnpm/issues/15383). 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). ##### 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 [#&#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). - Fatal peer dependency errors and their hints are now written to stderr [#&#8203;5419](https://github.com/pnpm/pnpm/issues/5419). - `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 run` and `pnpm exec` now print `No projects matched the filters in "<workspace>"` when `--filter` selects no project [#&#8203;8408](https://github.com/pnpm/pnpm/issues/8408). - `pnpm dedupe` now counts each package reused from the store once in its progress output [#&#8203;15303](https://github.com/pnpm/pnpm/issues/15303). - `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 link` now warns when linking a package that declares one or more peer dependencies, explaining that the linked dependency will not resolve peer dependencies from the target `node_modules` and suggesting the `file:` protocol instead. - `pnpm import` now warns when package.json lists projects in a "workspaces" array and there is no "pnpm-workspace.yaml". Without that file, the import writes a lockfile for the root project only [#&#8203;5240](https://github.com/pnpm/pnpm/issues/5240). - 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 --> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **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:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMTYuMSIsInVwZGF0ZWRJblZlciI6IjQ0LjEyNC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
renovatebot force-pushed renovate/all-minor-patch from 920b422a1d to 4b4f316207 2026-09-29 02:04:42 +02:00 Compare
renovatebot changed title from Update ghcr.io/immich-app/immich-machine-learning Docker tag to v3.2.4 to Update all non-major dependencies to v3.2.4 2026-09-29 02:04:51 +02:00
renovatebot force-pushed renovate/all-minor-patch from 4b4f316207 to 95234fb7fc 2026-09-29 08:04:30 +02:00 Compare
renovatebot changed title from Update all non-major dependencies to v3.2.4 to Update all non-major dependencies 2026-09-29 08:04:37 +02:00
renovatebot force-pushed renovate/all-minor-patch from 95234fb7fc to 8c65423f97 2026-09-29 14:04:21 +02:00 Compare
renovatebot force-pushed renovate/all-minor-patch from 8c65423f97 to 37dd3bd0c0 2026-09-29 20:03:39 +02:00 Compare
renovatebot force-pushed renovate/all-minor-patch from 37dd3bd0c0 to c771d6b836 2026-09-30 02:04:43 +02:00 Compare
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

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

Merge

Merge the changes and update on Forgejo.
git switch main
git merge --no-ff renovate/all-minor-patch
git switch renovate/all-minor-patch
git rebase main
git switch main
git merge --ff-only renovate/all-minor-patch
git switch renovate/all-minor-patch
git rebase main
git switch main
git merge --no-ff renovate/all-minor-patch
git switch main
git merge --squash renovate/all-minor-patch
git switch main
git merge --ff-only renovate/all-minor-patch
git switch main
git merge renovate/all-minor-patch
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
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
lilly/lillinfra!51
No description provided.