pnpm 12.5
pnpm 12.5 expands Python support with editable project packages, shared workspace
environments, automatic interpreter downloads, and lockfiles for multiple
platforms and Python versions. It also accepts Package URLs in pnpm add, adds
machine-wide task concurrency groups, and cleans up obsolete registry metadata
with pnpm cache prune.
Python projects and environments
Interpreters per project
pnpm install chooses an interpreter that satisfies
each project's requires-python, preferring .python-version when present.
Different projects can use different interpreters. Set python.executable to
choose one interpreter for every project.
When no installed interpreter fits, pnpm downloads a shared
python-build-standalone
interpreter and reuses it on later installs. runtimeOnFail
controls this behavior: download permits downloads, error fails, and warn
or ignore use an available interpreter despite the version mismatch.
Environments now live under python-envs in the pnpm store. Each project keeps
its .venv link, which the next install migrates from the old project-local
layout. Old .pnpm/python-envs directories remain until you delete them after
running programs stop using them. With frozenStore, environments remain local.
Wheel imports use packageImportMethod.
Choose clone-or-copy or copy when installed files may be modified. Isolated
build environments use clones or copies to keep backend writes private.
Editable packages and workspace sources
pnpm now installs a Python project's own package
editable when it declares [build-system], so its imports and [project.scripts]
commands work immediately. [tool.uv].package can override whether it is packaged.
Dynamic metadata comes from the build backend, and projects with only
requirements.txt can receive an environment and lockfile too.
Declare local dependencies through [tool.uv.sources]:
[tool.uv.sources]
shared = { workspace = true }
# Alternatively: shared = { path = "../shared", editable = true }
Build backends need approval through allowBuilds, using keys such as
'pkg:pypi/hatchling': true. Git dependencies and source distributions are also
supported and require distribution approval. Direct wheel URLs are supported.
A workspace dependency without a source declaration is refused instead of
silently fetched from an index.
One environment for a uv workspace
Members can share one environment:
[tool.uv.workspace]
members = ["packages/*"]
[tool.pnpm.python]
shared-environment = true
pnpm resolves every member into one pylock.toml and one .venv at the root.
Conflicting dependency requirements produce an error naming the members.
Independent environments remain the default.
Each project can also select its own extras and dependency groups
under [tool.pnpm.python]. Workspace defaults skip names a project does not
define; explicit project selections must exist.
One lockfile for multiple environments
Combine platform targets with Python versions:
supportedArchitectures:
- linux-x64-manylinux_2_28
- darwin-arm64
- win32-x64
python:
enabled: true
versions: ['3.12', '3.13']
Every platform is paired with every version. One pylock.toml
pins wheels and conditional dependencies for all of them. Installs select their
matching environment and reject interpreters outside the declared environments.
python.overrides and python.constraints control
versions throughout the graph. uv overrides and constraints are read too.
Python filtering now selects projects by name, path, and local-source dependency
relationships; pnpm add --filter <selector> pypi:<package> updates every selected
project.
Package URLs and ecosystem registries
pnpm add accepts Package URLs:
pnpm add pkg:npm/express@4.18.2
pnpm add pkg:cargo/serde@1.0.188
pnpm add pkg:pypi/requests@2.31.0
Each writes to its ecosystem's manifest. pkg is now a reserved registry alias,
regardless of case.
registries entries can name ecosystem: npm, cargo,
or pypi. Python searches indexes in declaration order and uses the first that
contains the package. Cargo accepts one sparse index. Credentials come from
.npmrc, matched by origin; registry URL keys cannot contain credentials.
This replaces python.indexUrl, python.extraIndexUrls, and cargo.indexUrl.
Without ecosystem declarations, PyPI and crates.io remain the defaults.
Platforms, tasks, and tool mirrors
supportedArchitectures
accepts a list of exact platforms, such as linux-x64, linux-x64-musl, and
darwin-arm64, or Rust target triples. current names the install's platform.
The existing os, cpu, and libc mapping still works.
concurrencyGroups limits
tasks across pnpm processes on the same machine, including pipelines:
tasks:
test:rust:
concurrencyGroup: cargo
concurrencyGroups:
cargo: 2
A nested pnpm run in the same group reuses its parent's slot.
tools configures mirrors for Node.js, Bun, and Python
in global config.yaml or PNPM_CONFIG_TOOLS. Node.js also supports per-channel
mirrors. Workspace tool mirrors are ignored, and pnpm pack-app uses tools.node
for its embedded runtime.
Cache cleanup and other fixes
pnpm cache pruneremoves obsolete metadata directories left by the registry cache naming change. Use--dry-runto preview deletions.pnpm cache list-registriesnow prints full URLs instead of encoded names.- Downloads no longer reuse a tarball for another package whose resolution pins a different integrity hash to the same URL (#15021).
- Production and development install filters keep the complete dependency graph
in
pnpm-lock.yaml, so a later frozen install accepts it (#14912). - Lockfile Git conflict markers are merged automatically (#14880).
- Cargo lockfile generation supports path and Git source overrides, and vendoring includes recursive Git submodules at their pinned commits.
pnxandpnpm dlxprompt for dependency build approval in interactive terminals, including cached installs with pending builds.- Python projects prepare concurrently, and identical registry requirements share
fresh resolutions.
pnpm auditalso avoids hangs on graphs with many shared dependencies.
See the v12.5.0 release notes for the complete list of changes.
