pnpm 11.8
pnpm 11.8 adds install dry-run previews, Node.js package map generation, richer SBOM output, pnpm view defaulting to the current package, and correct pnpm run --no-bail exit codes. It also includes a config-dependency lockfile traversal fix and many install/update determinism fixes.
Minor Changes#
pnpm install --dry-run#
pnpm install now supports --dry-run. It runs full dependency resolution and reports what a real install would change, but writes nothing to disk: no lockfile, no manifests, and no node_modules updates.
A completed dry run exits with code 0, matching the preview behavior of npm install --dry-run (#7340).
Node.js package maps#
pnpm now generates node_modules/.package-map.json during isolated and hoisted installs. The map describes how packages should resolve through the installed node_modules layout.
The new nodeExperimentalPackageMap setting injects the generated map into pnpm-managed Node.js script environments by adding Node's --experimental-package-map option to NODE_OPTIONS. The nodePackageMapType setting chooses between standard maps, which expose declared dependencies only, and loose maps, which also map packages reachable through the installed layout.
SBOM improvements#
pnpm sbom can now write SBOMs to files with --out, generate one SBOM per selected workspace package with --split, and use the selected package's metadata as the root component when --filter selects a single package.
CycloneDX output now marks components reachable only through devDependencies with scope: "excluded" and the cdx:npm:package:development property. Runtime components, including installed optional dependencies, keep the default required scope.
CLI behavior#
pnpm run --no-bail now continues running every matched script, but exits with a non-zero code if any script failed. Recursive runs already behaved this way; non-recursive runs now match them (#8013).
pnpm view can now be run without a package name. In that case it searches upward for the nearest project manifest and uses its name field.
Patch Changes#
- Security: Validate config dependency names and versions from the env lockfile before using them to build filesystem paths. A committed lockfile can no longer use traversal-shaped
configDependenciesnames or versions to write outsidenode_modules/.pnpm-configor the store. Names must be valid npm package names, and versions must be exact semver versions. See GHSA-qrv3-253h-g69c. - Fixed
pnpm updateoverriding the version range policy of a named catalog whose name parses as a version, such ascatalog:express4-21(#10321). - Fixed
link:workspace protocol dependencies switching tofile:afterpnpm rmwheninjectWorkspacePackages: trueis set and the target workspace dependency has its own dependencies. - Stopped warning about matching
packageManageranddevEngines.packageManagervalues when both pin the same package manager, version, and integrity hash (#12028). - Fixed interactive progress output leaving characters behind when external processes write to the terminal, such as SSH passphrase prompts (#12350).
- Fixed
pnpm approve-buildsmissing packages whose build approval was revoked and then re-added (#12221). - Skipped the redundant Windows warning about an existing
node.exewhen it already matches the target (#12203). - Fixed macOS Gatekeeper blocking native binaries imported from the store by removing the
com.apple.quarantineextended attribute from native binaries after import (#11056). - Fixed
optimisticRepeatInstallincorrectly reporting "Already up to date" when onlypnpm-lock.yamlchanged, and fixed the same checks for git branch lockfiles (#12100). - Fixed recursive updates that mix transitive dependency patterns with direct dependency selectors, such as
pnpm up -r "@babel/core" uuid(#12103). - Registered
pnpm update --no-savein CLI help and option parsing. - Fixed
pnpm importfor Yarn v2 lockfiles whenjs-yamlv4 is installed. - Fixed repeated reinstall prompts when
enableGlobalVirtualStoreis enabled by keeping the virtual store directory recorded during post-install builds aligned with the install step (#12307). - Documented the
--cpu,--os, and--libcflags inpnpm install --help(#12359). - Avoided reading
README.mdfrom disk during publish when the publish manifest already provides areadmefield. - Fixed
pnpm peers checkrejecting loose peer dependency ranges that the installed peer satisfies (#12149). - Preserved
workspace:dependencies that point at local paths duringpnpm update(#3902). - Fixed a lockfile non-convergence case where incremental installs could keep a duplicate transitive dependency that a fresh install would remove.
pnpm installdetects changes inside localfile:dependencies and local tarballs again, bypassing the optimistic fast path for those projects (#11795).- Preserved the existing Node.js runtime version prefix when resolving
node@runtime:<range>to a concrete version. - Shortened CAFS temporary package directories to leave room for lifecycle scripts that create IPC socket paths under
TMPDIR. - Reporter output for
pnpm storeandpnpm configsubcommands now goes to stderr, so scripts can safely capture stdout. - Avoided relinking unchanged child dependencies and removed stale child links during warm installs.
- Fixed lockfile churn where
transitivePeerDependenciescould be dropped or shifted when a package participates in a dependency cycle (#5108). - Fixed
pnpm installreporting "Already up to date" after a catalog entry inpnpm-workspace.yamlwas reverted to a previous version (#12418). - Kept lockfile
overridesthat resolve through a catalog in sync whenpnpm updatebumps the catalog entry. - Fixed
pnpm version --recursiveso it honors workspace selection instead of always bumping every workspace package (#11348).