Change8

v12.0.0-alpha.17

Breaking Changes
📦 pnpmView on GitHub →
2 breaking11 features🐛 7 fixes🔧 11 symbols

Summary

This release enhances pnpm's Git dependency handling, brings `pnpm list` and `pnpm why` to feature parity, and introduces new settings for workspace and dependency management. It also includes several bug fixes for build processes, dependency resolution, and engine checks.

⚠️ Breaking Changes

  • The `enableModulesDir: false` setting now correctly prevents the creation of a `node_modules` directory, unless the global virtual store is enabled. Previously, this setting might not have been fully honored in all scenarios.
  • Command shims now set `NODE_PATH` in a new way, reflecting the isolated `nodeLinker` with a hoist pattern. This might affect how Node.js resolves modules from shims if your project relies on specific `NODE_PATH` configurations. The new `extendNodePath: false` setting can be used to disable this behavior.

Migration Steps

  1. If you were relying on `node_modules` being created when `enableModulesDir: false`, you may need to adjust your setup if you are not using the global virtual store.
  2. Review your `NODE_PATH` configurations if your project relies on specific module resolution paths from command shims. Consider using `extendNodePath: false` if the new behavior is problematic.

✨ New Features

  • Added support for alias-less Git dependency adds.
  • Preserved locked Git commits during unrelated dependency changes.
  • Reported Git package versions in install logs.
  • `pnpm list` and `pnpm why` are now feature complete and behaviorally identical to the TypeScript CLI.
  • `pnpm list` gained `--only-projects`, `--find-by` (finders declared in `.pnpmfile.cjs`), search by version range (`pnpm ls "foo@^2"`), subtree deduplication with `[deduped]` markers, peer/skipped annotations, the package-count summary, `--long` manifest details, resolved tarball URLs and absolute paths in `--json`/`--parseable` output, and `--depth` support for globally installed packages.
  • `pnpm why` gained `--json`, `--parseable`, `--long`, `--prod`/`--dev`/`--no-optional`, `--find-by`, workspace project names in the reverse tree, dependency-field annotations, `[circular]`/`[deduped]` markers, peer-variant hashes, and the `Found N versions` summary.
  • Added support for the `cleanupUnusedCatalogs` setting: when enabled, `pnpm add`, `pnpm update`, and `pnpm remove` drop catalog entries from `pnpm-workspace.yaml` that no workspace project references.
  • Added the `--force` flag to `pnpm install` and `pnpm add`: optional dependencies whose `cpu` / `os` / `libc` / `engines` don't match the host are installed instead of skipped, and a forced install relinks packages that an earlier install already materialized.
  • `sharedWorkspaceLockfile: false` is now supported by the install family: a workspace install runs one dedicated install per project, each with its own `pnpm-lock.yaml`, `node_modules`, and virtual store (a custom `virtualStoreDir` resolves per project), and `pnpm add` / `update` / `remove` in a project operate on that project's own lockfile.
  • Added PnP install materialization.
  • Fixed recovery from expired module caches and broken private lockfiles.

🐛 Bug Fixes

  • Fixed recovery from interrupted dependency builds in the global virtual store.
  • Made `pnpm fetch` populate the virtual store without linking dependencies into projects.
  • Fixed workspace lifecycle ordering and bin linking across isolated and hoisted installs.
  • Auto-installed peer dependencies wanted by multiple packages under distinct but compatible ranges now resolve through the ranges' semver intersection (`2` + `^2.2.0` install one provider matching `>=2.2.0 <3.0.0-0`), matching pnpm. Previously such peers were only auto-installed when every consumer declared the identical range or `autoInstallPeersFromHighestMatch` was enabled.
  • `engineStrict` now fails the install when an incompatible package is reached through a regular dependency edge of an installable package, even if the package is also optionally reachable — matching pnpm. Packages reachable only through optional edges or skipped parents are still skipped.
  • Engine checks (`engines.node` / `engines.pnpm`) now match npm-semver's `includePrerelease` semantics exactly: a prerelease version no longer satisfies a fully specified `>=` bound (`9.0.0-alpha.1` does not satisfy `>=9.0.0`), while still satisfying expanded ranges like `9`, `>=9`, and `^9.0.0`.
  • Fixed a rare hang where `pnpm install` or `pnpm add` could wait forever: when two tasks fetched the same tarball concurrently, the waiting task could miss the downloader's completion notification and never wake up.

Affected Symbols