Sponsored Content
Skip to content

Releases

pnpm 12.20

Choose a tag to compare

@github-actions github-actions released this 12 Nov 00:23
Immutable release. Only release title and notes can be modified.
v12.20.0
ea74c2c

pnpm 12.20.0 records the specifiers of local directory dependencies in the experimental v13 lockfile and fixes several nodeLinker: hoisted, peer dependency, and overrides bugs. The bundled node-gyp no longer ships the undici version that security scanners flag. Remote resolution and shared build caches no longer work with pnpr 0.1.0-alpha.19 or older.

Minor Changes

  • With lockfile.format: v13, pnpm install records the dependency specifiers of local directory packages. Frozen installs reject changed specifiers even when the locked versions still satisfy them.

Patch Changes

Upgrading and security

  • Remote resolution, shared build caches, and release notes no longer work with pnpr 0.1.0-alpha.19 or older. pnpm now reads the capabilities a pnpr server advertises under pnpr.protocols. Installs fail when the server does not confirm the requested resolution and verification policies.

  • The node-gyp bundled with pnpm no longer ships undici 6, which security scanners flag for CVE-2026-84947. On Node.js 26, node-gyp downloads through a proxy or with a custom CA file no longer crash with "invalid onError method" #17941.

Resolving dependencies

  • Version-selector overrides entries such as "ms@^2.0.0": "2.1.1" now apply to dependencies declared with the catalog: protocol when the catalog entry's range matches the selector #17922.

  • A root overrides entry that points a package at a workspace: path, such as workspace:./packages/foo, now also applies when a registry package depends on that package pnpm/tasks#270.

  • Git dependencies now accept npm's :: separator between fragment parameters, such as github:owner/repo#v1.0.0::path:packages/foo. Before, pnpm read the whole fragment as a branch name and failed to resolve it #17827.

  • pnpm dedupe now keeps a locked runtime version, from devEngines.runtime or from a dependency's engines.runtime, when the declared range still admits it. pnpm dedupe --check no longer fails each time a newer Node.js release in the range comes out #17984.

  • With autoInstallPeersFromHighestMatch, conflicting non-semver peer dependencies now remain missing, and identical non-semver peer specifiers are preserved. Preferred registry versions no longer replace local paths or protocol-prefixed specifiers when pnpm installs missing peers pnpm/tasks#272.

Hoisted node linker

  • With nodeLinker: hoisted, a package now keeps its nested copy of a dependency that it resolved at a version other than the top-level one, including a peer dependency its parent supplies. Before, pnpm could remove that copy as a duplicate or give the top-level slot to a peer variant found deeper in the graph. The package then loaded the top-level version.

Lockfile and peer dependency graphs

  • Fixed pnpm install keeping stale peer bindings after dependency changes. Required dependencies no longer remain marked optional when another workspace project removes a shared package pnpm/tasks#221.

  • Repeated installs now keep the same dependency links when packages form cycles with several peer dependency variants pnpm/tasks#221.

  • Fixed writing lockfile.format: v13 for dependency cycles with missing, optional, or transitive peers. Frozen installs also accept unchanged injected packages whose peers use catalogs. With --no-optional, frozen installs reject required catalog children recorded only as optional dependencies pnpm/tasks#221.

  • pnpm deploy preserves an injected workspace package's resolved dependencies when they differ from the workspace project's own dependencies. This also applies to packages with publishConfig.directory pnpm/tasks#221.

Running scripts and runtimes

  • Scripts that pnpm runs in a process group of their own are now ended when pnpm is killed right after starting them. A parallel run that was killed before pnpm registered its scripts left all of them running.

  • When a command name matches no script and pnpm falls back to running it as a command, the install that runs before scripts now runs once. Its errors and warnings print once #17977.

  • Failed downloads by project-aware global runtime commands now explain which configuration applies. Node.js failures also list the global mirror settings and environment variables to check.

Other commands and settings

  • Fixed pnpm occasionally crashing on the first HTTPS request, mostly on Windows virtual machines under load. pnpm now seeds TLS randomness from the operating system's random number generator pnpm/tasks#239.

  • Fixed pnpm deprecate, pnpm undeprecate, and pnpm unpublish failing with revision conflicts when a registry cache serves stale package metadata.

  • pnpm sbom now reports malformed workspace manifests. Before, it omitted their packages pnpm/tasks#59.

  • Fixed pnpm store status reporting approved builds of git dependencies as modified when the store contains legacy build metadata.

  • pnpm now recognizes Capawesome Cloud and RWX as CI environments.

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit Cloudflare

Gold Sponsors

Sanity Discord Vite
Read more

pnpm 12.19

Choose a tag to compare

@github-actions github-actions released this 10 Nov 01:25
Immutable release. Only release title and notes can be modified.
v12.19.0
f4afab2

pnpm 12.19.0 adds pnpm fund, lets the loaded node linker handle packages that need a build, and adds the projectScopedOptionalPeers setting and an experimental JSON lockfile format. It also includes a security fix: an offline install error no longer prints registry credentials. pnpm now checks the engines and platform fields of every workspace project, and many hoisted-linker and frozen-lockfile bugs are fixed.

Minor Changes

  • Added pnpm fund, which lists the funding URLs declared by the installed dependencies in the same tree npm fund prints. Use --json for the npm fund --json report and --recursive or --filter to report on workspace projects. pnpm fund <pkg> opens the funding URL of an installed package, and --which picks one when it lists several #7354.

  • With nodeLinker.type: loaded, packages that need a build no longer have to be listed in nodeLinker.excluded. A package with a matching side-effects cache entry loads from the store. If side-effects cache reads and writes are enabled, pnpm builds an approved package once, saves the result to the side-effects cache, and then loads it from the store. This includes a build that changes no files in its package, so its script does not run again in other projects that use the same store. List a package in sideEffectsCache.exclude if its build must run in every project, such as a git hook installer. pnpm materializes other cache misses, packages with native .node addons, and their dependencies automatically.

    pnpm also scans JavaScript sources for filesystem imports and for __dirname or import.meta, and materializes matching packages. The scan does not detect computed imports. List such packages in nodeLinker.excluded.

  • Added the projectScopedOptionalPeers setting. When it is true, a project gets a missing optional peer dependency only if the project's own dependencies install a version of it. Another workspace project's dependencies, such as its devDependencies, no longer supply one. dedupePeerDependents keeps deduplicating everything else #16666.

  • Added the experimental lockfile.format: v13 setting. With it, pnpm writes pnpm-lock.yaml in a JSON-like syntax, indented with tabs, with a trailing comma after every entry. The file is still valid YAML. The file has one packages entry per package version in place of the packages and snapshots sections, and each entry records the versions of its peer dependencies as its properties. Updating a peer dependency then changes only the lines that record its version. pnpm reads lockfiles in both formats whatever the setting is.

  • pnpm store add now accepts directories of tarballs, such as pnpm store add ./tarballs, and adds every .tgz, .tar.gz, and .tar file inside them recursively. pnpm store add is now faster when it adds many packages or local tarballs #17875.

  • With supportedArchitectures set, pnpm install and pnpm fetch also store, without linking them, the dependencies of the archives kept for the other listed platforms. A platform added to the setting gets its archives and their dependencies on the next install. Optional dependencies a listed platform cannot run are not stored, and one that fails to download is skipped. Dependencies from git repositories are not stored for other platforms.

  • When supportedArchitectures names exactly one platform and not current, pnpm links that platform's variant of a package published with platform variants, together with that variant's dependencies. This holds for the list form and for the os, cpu, and libc form. A variant whose floor or ABI the listed platform does not state is not linked for it: pnpm links another variant that fits, or the version's own archive. Changing the setting, or the platform of the host, such as a node_modules mounted into a musl container or a Node.js with another ABI, relinks the package on the next install, even from a frozen lockfile.

  • pnpm now provides a prebuilt binary for NetBSD 10 on x64 #17803.

Patch Changes

Security

  • The error for a tarball that is missing from the store in offline mode no longer prints the credentials or token in the tarball URL.

Installs that failed or hung

  • pnpm install, pnpm ci, and pnpm install-test outside a workspace now fail with ERR_PNPM_NO_PKG_MANIFEST when the directory has no package.json, package.json5, or package.yaml. They no longer create a package.json, a lockfile, and node_modules there #17727.

  • Fixed pnpm install hanging when a concurrent tarball download or manifest read is cancelled while other tasks are waiting on the same archive.

  • Running a global command such as node in a project that pins its version no longer hangs while pnpm installs that version. The hang kept starting new processes until the machine ran out of memory.

  • A global command such as node now runs the version a project pins when PNPM_CONFIG_LOCKFILE_DIR, PNPM_CONFIG_VIRTUAL_STORE_ONLY, or PNPM_CONFIG_SYMLINK is set in the environment. Before, the dispatch failed with "the installed node executable is not under" the store.

  • pnpm install now fetches fresh metadata for a package when a version allowed by minimumReleaseAgeExclude is missing from the cached metadata. Before, it could fail with ERR_PNPM_NO_MATCHING_VERSION without contacting the registry #17723.

  • A ${VAR} placeholder in a registry URL in pnpm-workspace.yaml or the project .npmrc now fails the command. pnpm does not expand environment variables in these files. Before, pnpm ignored such a URL and resolved packages from another registry, such as npmjs.org. pnpm now warns when it ignores a placeholder in a proxy, pnprServer, or userAgent setting in pnpm-workspace.yaml #17762.

  • Fixed local package installs failing while a workspace lockfile is being written.

  • pnpm self-update and switching to the packageManager version now work behind a proxy that ends a response by closing the TLS connection without a close_notify alert. The registry signature check failed there with ERR_PNPM_PNPM_ENGINE_IDENTITY_UNVERIFIABLE #17763.

  • A package tarball that keeps failing to download now fails the install after fetchRetries retries. pnpm used to download it again with a second full set of retries, which doubled the wait. The error now names the actual download failure.

  • When the native binary of the pnpm version a project pins fails to download, pnpm now reports the download error. It used to report only that no native binary was found for the host.

  • POSIX bin shims and the pnpm, pn, pnpx, and pnx launchers now run inside a Nix build on macOS with the sandbox enabled. Installing again replaces the shims already in node_modules #17750.

  • Fixed pnpm leaving process pipes open after it exits on macOS pnpm/tasks#229.

Engines and platform checks

  • pnpm install, pnpm add, pnpm update, and pnpm remove now check the engines, os, cpu, and libc fields of every workspace project, including the workspace root. pnpm run -r and pnpm exec -r check them before running anything. An incompatible engines.pnpm fails the command. An incompatible engines.node prints a warning, or fails the command with engineStrict enabled. An unsupported platform prints a warning. A project that downloads its own Node.js through devEngines.runtime is checked against that Node.js #17751 pnpm/tasks#281 pnpm/tasks#299.

  • Fixed missing warnings when a required dependency does not support the current Node.js version.

  • An optional dependency that declares no os, cpu, or libc field is no longer skipped because its name contains only an operating system word, such as get-windows on macOS. pnpm now infers its platform from the name only when the name also has a cpu or libc token, such as -win32-x64 #17774.

Peer dependencies

  • With dedupePeerDependents: false, a missing optional peer is no longer resolved from a version that only another workspace project depends on. The workspace root's dependencies still count if resolvePeersFromWorkspaceRoot is true. Before, a tool in one project's devDependencies, such as webpack-cli, could become an optional peer of another project's production dependencies #16666.

  • pnpm install no longer gives a project an optional peer dependency that it skipped because a required peer would conflict with the project's dependencies. Before, dedupePeerDependents merged the project's copy of the package that declares the peer with another project's copy that resolves it #17781.

  • pnpm install no longer fills in a missing optional peer dependency if a required peer it brings in conflicts with a version the project depends on. Before, such a peer was installed along with it and reported as unmet #17718.

  • pnpm install --filter in a sparse checkout now counts the dependencies of workspace projects that are missing from disk when it resolves peer dependencies and marks packages as optional. The lockfile it writes no longer differs from a full checkout in those entries [#17791](#1...

Read more

pnpr 0.1.0-alpha.19

pnpr 0.1.0-alpha.19 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 10 Nov 01:28
Immutable release. Only release title and notes can be modified.
pnpr@0.1.0-alpha.19
f4afab2

pnpr 0.1.0-alpha.19 stores package metadata in PostgreSQL or MySQL as well as SQLite, stores identical archives once, and adds pnpr gc to reclaim unreferenced archives while serving. It does not migrate alpha.18 data, so read the upgrade steps below before you upgrade. It also includes a security fix: pnpr no longer logs the credentials of some malformed URLs. The release also tightens account, team, and publish validation.

Minor Changes

Upgrading from alpha.18

  • pnpr does not migrate alpha.18 data. At startup it refuses an alpha.18 metadata database or SQL auth database, including a local tokens.db, and leaves it unchanged. To upgrade:

    • Back up these databases, then delete pnpr's tables or point pnpr at new, empty databases.
    • Point storage or the s3: prefix at a fresh location. Hosted archives use a new layout. A fresh local storage directory also gives you a fresh SQLite metadata file.
    • Replace the backend and metadata blocks with database.url. pnpr refuses to start while either block is present.
    • Rename auth.htpasswd to auth.users. If accounts stay in the local account file, which is the case without database.url or with a sqlite: one, run pnpr import-htpasswd --source <old htpasswd> to bring over existing passwords. With any other database.url, recreate the accounts.
    • Passwords now need at least 8 characters, and pnpr checks this at login too. Run pnpr add-user <username> to set a new password for an account with a shorter one.
    • List account IDs, not usernames, in auth.admins, access lists, and OIDC bindings. Give each entry under teams a name and members.
    • Replace pnpr oci-gc and pnpr verify --prune-orphans with pnpr gc.
    • Recreate accounts and tokens, republish packages, and reconcile the SCIM directory with the identity provider. Recreated accounts get new IDs.
  • pnpr now runs numbered schema migrations for its metadata and auth tables. Each configured SQL database records its applied steps in its own schema_migrations table, starting at version 1.

Storage

  • pnpr can store package metadata in PostgreSQL and MySQL. Set database.url to share accounts, tokens, and package metadata in one database.

  • A hosted registry stores identical bytes once per org and ecosystem, whichever packages, versions, or image repositories publish them. A publish whose bytes are stored already stores nothing pnpm/tasks#269.

  • pnpr gc removes the archives that no hosted package maps, in every hosted npm, PyPI, Cargo, and OCI registry. It runs while the registry keeps serving and other replicas keep publishing. It removes the bytes of unpublished versions and packages, image blobs that no retained manifest reaches, and the archives of publishes that stopped or were refused at their commit. It also finishes interrupted reclaims. The new gc.lease setting sets how long an interrupted reclaim is left before another run finishes it. It defaults to 1h.

    pnpr verify no longer removes orphaned blobs. It still fails on missing or corrupted npm package blobs, and reports orphaned blobs in every hosted registry. Its --prune-orphans and --min-age options are removed.

Clients

  • The server applies the projectScopedOptionalPeers setting that a client sends, and records it in the lockfile it returns.

  • Added oci.chunkMaxBytes to advertise an upload chunk size to OCI clients that support OCI-Chunk-Max-Length.

Patch Changes

Security and access

  • pnpr no longer logs the credentials of a URL whose ? or # appears before @. It now redacts such a URL as <scheme>://redacted pnpm/tasks#301.

  • Renaming an account preserves its permissions and package ownership. Reusing a deleted username or team name starts with fresh permissions.

  • User lookups now require authentication. Team names and rosters are visible only to registry team members and administrators. New accounts cannot use usernames that look like an existing username.

  • pnpr now refuses stale authorization when a team roster, managed access rule, or SCIM directory read exceeds five seconds. A stalled roster or rule read no longer delays SCIM refreshes #17836.

  • Fixed MySQL-backed authentication failing to read case-sensitive usernames.

  • pnpr now keeps package ownership after unpublish, team rosters, rule overrides, SCIM users, and staged-publish metadata in its metadata database. An unpublish records ownership and removed versions atomically.

Publishing npm packages

  • npm publishes now reject package names that npm disallows for new packages, including uppercase letters and an @ in the package part. Existing upstream packages remain readable.

  • pnpr rejects publishes when a version key or manifest version is not valid semver pnpm/tasks#267. Publishing a version key with build metadata returns an explicit error. DELETE requests for invalid versions return 400.

  • A tarball DELETE of a version that the package still lists unpublishes that version.

  • Retrying an identical publish of an unpublished version now returns 403. Batch publish retries also fail if any published member has been unpublished.

  • Stale partial unpublish and deprecation requests now fail with 409. Deprecation requests preserve dist-tags and other package metadata.

  • Dist-tag writes now reject names that parse as semver ranges and targets that are not published versions. Removing latest is rejected while published versions exist.

  • Release note edits and deletions no longer retain earlier text for restoration.

Other ecosystems

  • Deleting the last manifest of an OCI repository now removes the repository from /v2/_catalog, and GET /v2/<name>/tags/list answers 404 NAME_UNKNOWN until another manifest is pushed. DELETE /v2/<name>/blobs/<digest> now answers 403 DENIED when a retained manifest still references the blob.

  • Deleting an OCI manifest by digest now invalidates the saved batch publish outcomes that include it. Deleting an OCI tag leaves batch replay intact. A deleted OCI manifest can be published again.

  • The Python registry proxy now supports core-metadata declarations and caches .metadata downloads. pip and uv can read dependency metadata without downloading whole wheels.

  • Python uploads now reject unreadable archives and metadata that names a different project or version. Publishers can change the yank status of individual files. Administrators can delete files from the index and disable their downloads. Deletion retains stored archive bytes.

  • Cargo package claims now cover both - and _ spellings. Requests for a hosted crate cannot fall through to an upstream registry under the alternate spelling. New versions must use the spelling of the crate's first published version.

  • Cargo sparse index files now send ETags and return 304 Not Modified when the client already has the current content.

Speed and caching

  • Large package metadata requests no longer block unrelated registry requests. Repeated requests reuse rendered metadata while the package content is unchanged.

  • Sped up publishing with an Idempotency-Key header.

  • Responses for public packages read through a named registry, such as /npm/~npmjs/<package>, are now cacheable by shared HTTP caches. Packages that need authentication still get Cache-Control: private, no-store. PyPI project pages now send Vary: Accept.

  • A tarball that pnpr downloads from an upstream registry is no longer cut off after the upstream timeout while it is still arriving. The timeout now limits how long pnpr waits for the upstream to answer and for each further part of the download. Before, a tarball that took longer than 30 seconds to download from a slow upstream failed every time.

  • Response body timeouts no longer open an upstream's circuit breaker. Circuit-open responses name the upstream and include Retry-After.

Responses and logs

  • npm clients now display the server's explanation when a registry request fails. Authentication errors distinguish invalid tokens from missing credentials. A 401 response includes a WWW-Authenticate challenge.

  • Package metadata responses no longer include the internal formatVersion field or access: null.

  • Fixed npm search failing on hosted packages with maintainer names. Search results for hosted packages no longer link to an external package website.

  • pnpr logs scoped package URLs such as https://registry.npmjs.org/@babel/cli with their registry host intact. It previously logged them as https://redacted@babel/cli.

pnpm 12.18

Choose a tag to compare

@github-actions github-actions released this 05 Nov 00:56
Immutable release. Only release title and notes can be modified.
v12.18.0
0470052

pnpm 12.18.0 packs, publishes, and installs packages with platform variants on pnpr registries. It also adds per-skill approval of agent skills and pnpm store add for offline installs from downloaded tarballs. Repeat installs and verifyDepsBeforeRun no longer read the package.json of unchanged workspace projects. The release fixes several peer dependency resolution bugs too.

Minor Changes

Agent skills

  • pnpm now names the link to a dependency's agent skill after the skill alone. A skill that the @acme/kit package ships in skills/auth/ is linked as .claude/skills/auth, not .claude/skills/pnpm-@acme+kit-auth. The next install replaces links with the old names. pnpm lists the linked skills in a # pnpm block of each agent skill directory's .gitignore #17455.

    When two approved packages ship a skill of the same name, or the name is already taken in an agent skill directory, pnpm links the skill as pnpm-<package>-<skill>. Before, the install failed.

  • pnpm approve now asks which agent skills to link when a package ships more than one. pnpm records the chosen skills as a list, such as permissions.<pkg>.skills: [guide, migrate], and does not offer the other skills for approval again. The first time a project approves a skill, pnpm approve also asks which agent directories to link skills into, and records the answer under skills.dirs.

  • pnpm links agent skills nested in category directories, such as skills/engineering/implement/SKILL.md, up to three levels below skills/. Before, it linked only the skills directly under skills/.

Platform variants

These features need a registry declared with serverType: pnpr.

  • pnpm pack packs one archive per entry of publishConfig.variants, each platform variant as <name>-<version>~<tag>.tgz. pnpm pack --variant <target> packs only the archive whose entry lists that target. pnpm pack --json prints the integrity and size of every archive it writes.

  • pnpm publish publishes a package's publishConfig.variants. pnpm uploads every archive before the publish request that references them. Publishing variants to any other registry is refused unless --no-variants is given, which publishes only the archive that targets any.

  • pnpm publish --upload-variant <target> uploads the archive of one publishConfig.variants entry to the registry's staging area and prints <target>=<integrity>. pnpm publish --variant-integrity <target>=<integrity> then publishes the version from archives that other jobs uploaded. With --recursive, each value names its package as <name>~<target>=<integrity>.

  • pnpm publish -r --batch now uploads each package archive on its own request and skips archives the registry already holds, so the batch request no longer grows with the archives it publishes. A batch of more than 256 packages still carries every archive inline. Packages with publishConfig.variants can be published in a batch. A batch with variants that would reference more than 256 archives on one registry fails with ERR_PNPM_BATCH_PUBLISH_TOO_MANY_ARCHIVES pnpm/tasks#244.

  • pnpm publish --provenance signs one statement that names every archive of a version with publishConfig.variants. A platform variant's archive is named by the version's package URL with a variant qualifier.

  • Rerunning pnpm publish after the version was already published now succeeds when the published version is the same release. pnpm compares the archives, the provenance statement when the rerun signs one, and the dist-tag. When the published version differs, the publish fails with ERR_PNPM_PUBLISHED_RELEASE_DIFFERS, which names what differs.

  • pnpm installs the platform variant of a package that fits the host, or the package's own archive when none does. The lockfile records every variant. A version published with variants only, and no archive for other hosts, installs on a host one of the variants fits. On any other host, an optional dependency is skipped, and any other dependency fails with an error that lists the platforms the version is published for.

  • supportedArchitectures platform lists accept platform tags, the same tags publishConfig.variants entries name. An entry can state floors and an ABI, such as linux-x64-manylinux_2_28, darwin-arm64-macos_14_0, linux-x64-napi8 or linux-x64-node127, and any Node.js OS and CPU, such as freebsd-x64. The spellings accepted before still work.

  • With supportedArchitectures set, pnpm also fetches into the store the variants that the other listed platforms need, when it downloads a package with platform variants.

pnpr registries

  • pnpm downloads less metadata from a registry declared with serverType: pnpr. A large package document leaves out the manifests of rarely picked versions, and pnpm fetches one only when it picks that version. In a benchmark that resolves 787 packages, the package documents shrank from 30.3 MB to 2.5 MB gzipped. pnpm caches these documents in v12/metadata-pnpr, and the pnpm cache commands cover them.

    pnpm warns when a registry that is not declared serverType: pnpr turns out to be pnpr. For a registry declared serverType: pnpr, a minimumReleaseAge longer than 30 days fails with ERR_PNPM_UNSUPPORTED_MINIMUM_RELEASE_AGE.

  • pnpm publish sends release notes to registries declared with serverType: pnpr. A package's notes are the section for its version in CHANGELOG.md, or the notes that pnpm version -r composed from change intents. --release-notes <file> gives the notes from a file, and --no-release-notes sends none. --publication-name names a release published with --batch.

    In a workspace that uses pnpm's versioning, pnpm version -r --release-notes <file> puts a summary above the composed notes of the release.

    pnpm view <pkg>@<version> releaseNotes, pnpm outdated --notes, and pnpm update --interactive show the release notes from these registries.

Store and hooks

  • pnpm store add now prepares the store for offline installs from package tarballs downloaded some other way. After pnpm store add ./tarballs/*.tgz, pnpm install --offline --frozen-lockfile installs each registry package whose lockfile entry pins one of those tarballs #2978.

  • Custom pnpmfile fetchers can use fetchers.gitHostedTarball, fetchers.git, and fetchers.binary pnpm/tasks#191.

Patch Changes

Installing packages

  • Running node or pnpm install in a project that pins a Node.js version pnpm has not downloaded yet no longer hangs when a globalPnpmfile is configured #17530.

  • pnpm install with enableGlobalVirtualStore no longer fails on Windows for a dependency from a named registry, such as gh: or npmjs: #17665.

  • Concurrent installs that share a global virtual store no longer fail with ERR_PNPM_CMD_SHIM_SYMLINK_BIN when they link the same executable at the same time #17587.

  • pnpm install and pnpm ci now succeed when dependency skills are approved but no agent skill directory exists. The skills stay unlinked until a directory exists #17574.

  • Commands run from a workspace package now use the same default store as the workspace root. Before, pnpm add in a package could fail with ERR_PNPM_UNEXPECTED_STORE when the workspace root was its own mount point and the home store was on another volume, as in a sandbox or a container.

    A workspace installed with the old behavior may need one pnpm install --force from the workspace root.

  • pnpm deploy now keeps a symlink in the project whose target is missing from the source, such as a link into a node_modules directory that was removed after the build. Deploy used to drop such a link silently #17571.

  • pnpm install now links the runtime that an earlier pnpm install --no-runtime skipped, and pnpm install --no-runtime removes a runtime that an earlier install linked #17542.

  • With enableGlobalVirtualStore, pnpm install again runs a dependency's build scripts in a project whose global virtual store slot another project already built, unless the side-effects cache has build output to restore for it. A build that writes only outside its own package, such as a git hook installer, now takes effect in every project #17526.

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

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

Lockfile and local paths

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

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

  • pnpm install --frozen-lockfile now accepts a lockfile written with excludeLinksFromLockfile and linkWorkspacePackages on, when a project depends on a ...

Read more

pnpm 11.28.11

Choose a tag to compare

@github-actions github-actions released this 05 Nov 01:00
Immutable release. Only release title and notes can be modified.
v11.28.11
0470052

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

Patch Changes

Installing packages

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

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

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

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

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

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

Lockfile and resolution

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

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

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

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

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

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

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

verifyDepsBeforeRun

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

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

pnpm link

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

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

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

pnpm update

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

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

Store and self-update

  • pnpm store prune now keeps packages linked from a configured modules directory pnpm/tasks#230.

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

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

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

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit Cloudflare

Gold Sponsors

Sanity Discord Vite
Read more

pnpr 0.1.0-alpha.18

pnpr 0.1.0-alpha.18 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 05 Nov 01:03
Immutable release. Only release title and notes can be modified.
pnpr@0.1.0-alpha.18
0470052

pnpr 0.1.0-alpha.18 keeps hosted package metadata in SQLite or a shared libSQL database, logs release records in transparency logs, and accepts packages with platform variants. The documents metadata backend is gone, so packages hosted by an earlier pnpr have to be published again.

Minor Changes

Metadata storage

  • pnpr now keeps hosted package metadata in SQL only. By default it uses a SQLite database at <storage>/.metadata/metadata.sqlite. The metadata block names another database by URL, such as url: sqlite:./metadata.sqlite. The documents metadata backend is removed, and a config that sets metadata.backend or metadata.path is refused.

    pnpr does not import the metadata of an existing store. A store that kept its metadata as documents starts with empty metadata, so republish its packages after upgrading. An s3: store that hosts packages needs a libSQL metadata.url. migrate-storage moves archives only and needs that libSQL database to hold the metadata already.

  • pnpr can keep hosted package metadata in a libSQL database, such as Turso, shared by several pnpr instances. Set metadata.url to a libsql:// URL. It works with an s3: block, so archives stay in object storage. With metadata.replicaPath, each instance reads package documents from a local replica that syncs every metadata.syncInterval. Permission checks and the reads a write depends on always read the primary.

  • pnpr refuses any change to a published npm version's manifest, and never accepts an unpublished version again. pnpr records who moved each dist-tag, and when. Hosted npm package responses carry a pnpr-generation header.

  • A reader sees all of a publish or batch publish, or none of it. A retried publish gets its original response instead of a 409. Batch publishes accept an Idempotency-Key header. pnpr records each publish as a publication and serves it at /-/publications/<org>/<id-or-name>.

  • pnpr stores release notes for package versions and publications. A publish can include them in a notes field. Publishers can edit or delete a note later. npm clients read a version's note at /npm/<name>/<version>/notes. A package's notes are listed at /npm/<name>/-/notes. A publication's note is at /-/publications/<org>/<id-or-name>/notes.

Publishing

  • A hosted pnpr registry rejects a publish whose version metadata disagrees with the package.json inside its archive. Its 400 response names the package, the version, and each differing field. pnpr checks the dependencies, the platform fields, bin, and the install scripts. pnpr also rejects a publish whose archive does not decode or holds more than one package.json.

    pnpr accepts the rewrites that npm and older clients make while publishing, such as a bin string expanded into an object. pnpr publishes a version without semver build metadata. pnpr serves a version's checked fields as its archive states them, with hasInstallScript and _hasShrinkwrap always set. Other fields, such as description, are served as submitted.

  • pnpr accepts release archives uploaded by integrity before the publish that references them, through PUT /-/pnpr/v0/artifacts/blob?integrity=<sha512-…> without an owner #17608. An npm publish, alone or in a batch, can then reference a staged archive: the attachment carries the archive's integrity in place of data. A version and its platform variants therefore no longer have to fit in one request body. An archive the publishing account has not staged, or one that has expired, fails the whole publish.

  • Trusted-publishing workload credentials can stage archives for the packages they are configured for, and send batch publish commits for those packages. A batch entry for any other package, or of another ecosystem, is refused.

  • A hosted registry that declares tarballs: tar now stores each published version as one tar compressed with zstd at level 19, and no .tgz. A client that accepts zstd gets those bytes, so even its first download is at level 19. Any other client gets the tar decoded, gzip-encoded if it asks for gzip.

    pnpr now refuses to start when a router without tarballs: tar lists such a registry as a source. Versions that an earlier pnpr published to such a registry are no longer served. Publish them again.

Package documents and platform variants

  • pnpr serves its own package document to clients that ask for application/vnd.pnpr.install-v2+json. A large document leaves out the manifests of rarely picked versions. It serves each version's release record at <name>/<version>+r<revision>. npm's documents served by pnpr no longer carry dist.pnpr, dist.revision, or dist.revisions. The new packageDocuments setting configures the split threshold and the publish-time window.

  • pnpr accepts platform variants with a published version and serves each one at <name>@<version>/variants/<tag>. Only pnpr's own package document lists them, so npm clients install the version's own archive.

  • pnpr accepts a version published with platform variants only, without an archive for every other host. It generates the archive that npm's documents point to, whose package.json lists the variants' platforms, so npm reports an unsupported platform instead of installing an empty package.

  • pnpr rejects a version published with a provenance statement that does not name each of its archives by its package URL and SHA-512. A platform variant's archive is named by the version's package URL with a variant qualifier, which its release record entry lists as purl.

Release records and transparency logs

  • A hosted npm version is accepted with its release record, and <name>/<version>+r0 serves the record's bytes as they were accepted. The record starts with the fields every release record has: schema, purl, revision, interpretation, the profile its manifest was derived under, and inputs, the digests of the .tgz and the package.json it was derived from. Each platform variant lists its own inputs.

  • pnpr logs the release records of the npm versions it hosts. Each hosted organization has a transparency log per ecosystem, in the C2SP tiled log format. A version's log entry is recorded in the same transaction that accepts the version. With releaseRecords.logSigningKey set, pnpr then adds the entry to the log's tiles and signs a new checkpoint, keeping both in the hosted store.

  • A hosted registry serves the transparency log of its release records under /-/log/: the latest checkpoint, the hash tiles, and, for callers who may read every package of the organization, the entry bundles. A release record's evidence, <name>/<version>+r<revision>/evidence, holds the record's digest, the inclusion proof of its log entry against the log's checkpoint, and the version's provenance bundle. GET /-/pnpr lists records and manifestProfiles when the records are logged.

  • With releaseRecords.statementSigningKey set, a release record's evidence carries the registry's acceptance statement: a signed in-toto Statement saying the registry accepted the record under its profile. pnpr signs it from the accepted record each time it is read, so rotating the key signs every statement again.

Patch Changes

  • A resolve request keeps plain lockfile keys for packages from its default registry, even when a prefix such as npmjs points at that registry #17575.

  • pnpr no longer frees a package name when a package deletion fails partway. pnpr no longer restores an unpublished version when it finishes an interrupted publish at startup.

  • pnpr config check now prints the S3 key prefix as plain text, such as prefix: pnpr/, and leaves it out when none is set. It printed prefix: Some("pnpr") or prefix: None.

pnpm 12.17

Choose a tag to compare

@github-actions github-actions released this 30 Oct 14:24
Immutable release. Only release title and notes can be modified.
v12.17.0
896dc10

pnpm 12.17.0 adds pnpm peers check --global, dependency-group selectors and wildcards in overrides, and runtime, package manager, Cargo, and Python updates in pnpm outdated and pnpm update. It also fixes files that other users could not read in Docker images, and repeat installs that missed changes to local dependencies.

Minor Changes

  • pnpm peers check now accepts --global (-g) to check globally installed packages. After a global install or update, the peer dependency warning now suggests pnpm peers check -g #17504.

  • pnpm outdated and pnpm update now inspect and update package manager and runtime versions in devEngines.packageManager, packageManager, devEngines.runtime, engines.runtime, and runtime: dependencies. With cargo.enabled or python.enabled, pnpm outdated and pnpm update also inspect and update Cargo dependencies in Cargo.toml and Cargo.lock and Python dependencies in pyproject.toml and pylock.toml.

  • overrides selectors now support :prod, :optional, and :peer pseudo-selectors that target a single dependency group. They also support * wildcard patterns on parent and target package names. An override with a non-range value, such as npm: or file:, no longer adds a peer dependency to dependencies. Removing an optional dependency with "-" now also removes the duplicate entry from dependencies #5391.

Patch Changes

Installing packages

  • Files that pnpm creates in a project now get the permissions the umask gives any new file, such as 0644. Before, several of them were readable only by the user who ran pnpm, which broke Docker images that run as a different user #17435.

    The fix applies to:

    • node_modules/.pnpm-workspace-state-v1.json. A different user running pnpm run reinstalled the dependencies because it could not read this file.
    • pnpm-workspace.yaml
    • the files written by pnpm deploy
    • patch files from pnpm patch-commit
    • the lockfile restored by pnpm dedupe --check
    • the Cargo and Python files that pnpm writes

    When pnpm edits an existing file, the file keeps its permissions.

  • pnpm install no longer writes broken dependency links when the project's node_modules is a symlink to another directory, such as another project's node_modules. The install reported success, but the links it wrote did not resolve #17448.

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

  • When pnpm switches to the version a project pins, it now installs that version's native binary for the current host, even if the project's supportedArchitectures excludes the host. Before, pnpm could not use the pinned version and kept running the installed one. pnpm also repairs a pinned version that an earlier install left without the host's binary.

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

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

  • With nodeLinker: hoisted, when two workspace projects need the same package version and it cannot be hoisted to the root, each project now keeps the copy installed in its own node_modules. Build scripts run in each of these copies. Before, the second project's copy was replaced with a symlink to the first project's, so every repeat install imported it again #17498.

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

  • Hardlinking from the store now stats each store file once per install. Since pnpm 12.8.0, a store file was stat'ed again for every package that links it. On an offline install of a large workspace, that added up to 15% system CPU #17500.

Repeat installs and local dependencies

  • pnpm install --frozen-lockfile no longer reports an outdated lockfile right after the install that wrote it. This happened when a pnpmfile readPackage hook or packageExtensions changed the dependencies or peer dependencies of a local directory dependency outside the workspace projects. It affected a file: dependency, an injected workspace:../dir dependency outside the workspace patterns, and an injected workspace package left out by --filter #17447 #17473.

    A repeat pnpm install now takes the fast path when ignoredOptionalDependencies removes an optional dependency of a file: directory dependency. It used to resolve again on every run.

  • pnpm install now resolves again after an edit to an injected workspace:../dir dependency outside the workspace patterns under a shared lockfile. It used to keep the lockfile unchanged. The next pnpm install --frozen-lockfile then failed #17476.

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

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

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

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

  • A repeat pnpm install reports "Already up to date" again when a pnpmfile readPackage hook changes the dependencies of a workspace project. Since 12.15.0, every such install ran in full #17468.

    After an edit to a project's package.json, pnpm install and verifyDepsBeforeRun now run the pnpmfile's readPackage hook on the edited manifest before comparing it with the lockfile. They could report the project up to date when the hook rewrote the edited dependency to a specifier the lockfile did not record.

Adding and updating dependencies

  • pnpm update --latest with package selectors now updates the dependencies of the selected packages within their declared ranges. Excluded packages and their dependencies keep their locked versions #17444.

  • pnpm add <pkg>@<tag> now uses a catalog entry set to that same dist-tag. The dependency is saved as catalog: and the entry stays as written pnpm/tasks#225.

    When pnpm add adds a new dist-tag such as vue@legacy to a catalog, the catalog entry records the exact version the tag points to. The same applies to a dependency added without a version when the tag setting names a dist-tag other than latest.

  • pnpm add now saves the resolved version range of an npm alias. For example, pnpm add v2@npm:vue and pnpm add v2@npm:vue@^3.0.0 both save npm:vue@^3.5.13.

Running scripts and commands

  • Programs that a script or pnpm exec command leaves running, such as a browser opened by the open package, now outlive pnpm exactly when they would outlive the command run without pnpm. Before, on Windows, a failed command, Ctrl+C, or a closed terminal ended all of them. pnpm still ends them when it is killed or crashes.

    When a recursive or parallel run bails, the scripts still running now receive SIGTERM on Unix and are killed only if they are still running two seconds later. On Windows, everything those scripts started is ended, including detached processes whose parent has already exited. Before, a bail killed them at once #17465.

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

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

  • pnpm --env-file now reads files the way node --env-file does. Values are taken as written, so $VAR is no longer expanded and Windows paths such as C:\Users\me load unchanged. A file is no longer rejected for its contents.

Settings and messages

  • pnpm version no longer creates a git commit and tag when `gi...
Read more

pnpm 11.28.10

Choose a tag to compare

@github-actions github-actions released this 30 Oct 21:18
Immutable release. Only release title and notes can be modified.
v11.28.10
896dc10

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

Patch Changes

Installing packages

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

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

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

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

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

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

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

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

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

Repeat installs and lockfiles

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

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

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

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

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

Adding and publishing packages

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

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

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

Running commands

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

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

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

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

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit Cloudflare

Gold Sponsors

Sanity Discord Vite
SerpApi ...
Read more

pnpm 12.16.1

Choose a tag to compare

@github-actions github-actions released this 27 Oct 15:28
Immutable release. Only release title and notes can be modified.
v12.16.1
c7b46ae

This release fixes pnpm install hanging on a cold store in workspaces that install Cargo crates, and pnpm pack shipping a file that files excludes by name.

Patch Changes

  • pnpm install no longer hangs on a cold store in a workspace that also installs Cargo crates or a Rust toolchain.

  • pnpm pack and pnpm publish now apply a files entry that names a file after the glob and directory entries, as npm does. A file excluded by name, such as !dist/index.js, stays out even when a later dist/** matches it. A file named by its path, such as lib/secret.js, ships even when a later !lib/*.js matches it.

  • pnpm install no longer leaves a broken symlink in an injected workspace dependency when the package links to a file outside its published files and pnpm imports by hardlink. Installing a git dependency now skips internal directory symlinks when importing its files into the store.

  • pnpm install now relinks a command that a workspace project renames into the projects that depend on it when sharedWorkspaceLockfile is false pnpm/tasks#224.

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

  • pnpm install now reads a package's manifest to decide its peer dependencies when it updates an existing lockfile, as it does when it resolves from scratch.

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

  • pnpm now accepts the --cache-dir <dir> flag, as in pnpm install --cache-dir /tmp/pnpm-cache #17422.

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

Platinum Sponsors

Bit OpenAI Notion
CodeRabbit

Gold Sponsors

Sanity Discord Vite
SerpApi Stackblitz Workleap
Nx Latitude

pnpm 12.16

Choose a tag to compare

@github-actions github-actions released this 27 Oct 00:12
Immutable release. Only release title and notes can be modified.
v12.16.0
6b5b8ac

This release adds a global --env-file flag, updates to a symlinked pnpm-lock.yaml, and pnpm setup --no-modify-path. It also fixes two security issues, in zstd decompression and in signing.

Minor Changes

  • Added a repeatable global --env-file <path> flag to load environment variables from dotenv-style files before running a command. Later files override earlier files, variables already in the environment are preserved, and loaded variables are visible to user-level .npmrc interpolation and lifecycle scripts #7111.

  • pnpm can now update a pnpm-lock.yaml that is a symlink. List the directories the lockfile may link into in the symlinkedLockfileTargetDirs setting, in the global config or with PNPM_CONFIG_SYMLINKED_LOCKFILE_TARGET_DIRS. pnpm writes the update to the file the symlink points to if that file is inside one of these directories. The symlink stays in place. pnpm ignores this setting in pnpm-workspace.yaml #17222.

  • Added a --no-modify-path option to pnpm setup. It installs pnpm without adding it to PATH, leaving the shell config file, the Windows registry, and the GitHub Actions environment files unchanged. pnpm setup then prints the lines to add yourself get.pnpm.io#37.

Patch Changes

Security

  • Fixed memory exposure and allocation handling vulnerabilities when processing zstd-compressed data #17388.

  • Signing in pnpm and pnpr no longer uses arithmetic that may leak the private key through timing. This covers shared artifacts, OCI registry tokens, and OIDC login state advisory.

Installing packages

  • A dependency symlink that pnpm cannot point at the wanted target now fails the install with an error that names the link. This happens when the filesystem still serves the old link after pnpm removed it, as a node_modules served by a virtual filesystem does. pnpm used to remove the link again without end and crashed with a segmentation fault once the thread ran out of stack.

  • Concurrent workspace installs no longer lose store-index rows when initializing the shared SQLite index #17388.

  • Agent skill links now keep the same target across installs when a package version is installed with several sets of peer dependencies. An install no longer fails with ERR_PNPM_AGENT_SKILL_PATH_OCCUPIED on a skill link that pnpm created for another of those copies #17319.

  • pnpm now fails at once, without retrying, when a downloaded package archive contains a rejected entry path #17205.

  • pnpm now builds a git-hosted dependency in every new location it links the dependency into, such as a new global virtual store slot or a fresh node_modules. When the side-effects cache holds the build output, pnpm restores it from there. Before, only the install that fetched the dependency built it. This also fixes dependencies that are already in the store #17224.

  • Changes a preResolution hook makes to the lockfiles now take effect. The hook now also runs when pnpm installs from an up-to-date lockfile. An error thrown by the hook now fails the install.

  • A custom fetcher in the pnpmfile can now call fetchers.directory to fetch a package from a local directory. The call rejects with ERR_PNPM_TARBALL_INTEGRITY if the lockfile pins an archive integrity for the package. Previously, calling fetchers.directory failed with a TypeError.

  • packageImportMethod: copy now also applies to packages that have lifecycle scripts or patches. On a filesystem that supports block cloning, such as ReFS or a Dev Drive on Windows, these packages were cloned #17195.

  • With nodeLinker: hoisted and autoInstallPeers: false, a package that workspace projects use with different peer versions is now installed once per peer variant, so each project's copy resolves that project's peer #17395.

  • Under nodeLinker: hoisted, pnpm install now leaves a patched package that is already in place alone. The same holds for a package whose peers include a patched package, such as every package peering on a patched react-native #17188.

  • With nodeLinker: hoisted, an install that stops partway no longer leaves the next install trusting the packages it was replacing. Before, reverting the change that started the stopped install, such as a patch edit, kept the half-replaced package in node_modules.

Repeat installs and changed settings

  • A repeat pnpm install now acts on a change to these settings. Before, it reported "Already up to date".

    • storeDir or virtualStoreDir: it recreates node_modules.
    • globalVirtualStoreDir: it links the packages from the new directory.
    • virtualStoreDirMaxLength: it renames the virtual store directories.
    • dangerouslyAllowAllBuilds turned on: it runs the builds it skipped.
    • trustLockfile turned off: it verifies the lockfile.
  • pnpm add, pnpm remove, and pnpm update now fail if node_modules does not match the current settings. Run pnpm install to recreate it. Previously, these commands removed and reinstalled node_modules without asking. They report:

    • ERR_PNPM_UNEXPECTED_STORE if node_modules was linked from a different store.
    • ERR_PNPM_UNEXPECTED_VIRTUAL_STORE if it was linked from a different virtual store directory.
    • ERR_PNPM_MODULES_BREAKING_CHANGE if it was installed by an incompatible pnpm version, or if node_modules/.modules.yaml cannot be read.
    • ERR_PNPM_NODE_LINKER_DIFF if it was installed with a different nodeLinker.

    pnpm update now also fails with ERR_PNPM_HOIST_PATTERN_DIFF and the other errors pnpm add reports for a changed hoist pattern or virtualStoreDirMaxLength.

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

  • pnpm install and the verifyDepsBeforeRun check now notice an edited patch file when sharedWorkspaceLockfile is false.

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

  • pnpm install now relinks the bins of a workspace package when its bin field changes, including with --frozen-lockfile and an unchanged lockfile. A filtered install relinks them in the selected projects, and the next install that covers the remaining projects relinks them there #17324.

  • pnpm install now removes command shims from node_modules/.bin when a workspace dependency renames or removes an entry from its bin field pnpm/tasks#211.

Resolving dependencies and the lockfile

  • A package that a plain range and a <prefix>: specifier both resolve from one registry is now recorded once in pnpm-lock.yaml and installed once. The lockfile key names the registry a package resolved from. When that registry declares a prefix, through prefix in registries or through namedRegistries, the package is keyed <name>@<prefix>:<version> however its dependency was written: with the prefix, as a plain range its scope routes to that registry, or through the default registry. Before, the plain range was keyed <name>@<version>, so one tarball was installed twice and instanceof checks and module singletons broke between the two copies. The same name and version served by two registries still get separate entries. When several prefixes declare one registry, its packages are keyed by the lexicographically smallest prefix.

    If a scope you route reaches a registry that also declares a prefix, your next pnpm install re-keys those entries, which shows up as a lockfile diff. Commit it. pnpm install --frozen-lockfile installs the lockfile as recorded.

  • pnpm install now resolves a scope's packages again when the scope is routed to another registry in registries. Before, the lockfile kept the versions and integrity resolved from the old registry, so the install failed when the new registry did not serve a locked version or served different content. pnpm records in the workspace state which registry each scope routed to, so a fresh clone without that record installs the lockfile as recorded. Changing the default registry resolves nothing again, and pnpm install --frozen-lockfile is unchanged.

  • When autoDedupe is off, a workspace project's dependencies now resolve from its own ranges, like they do with sharedWorkspaceLockfile: false. Previously, another project's narrower range could hold them back. For example, ajv: "*" now resolves to the latest Ajv even if another project depends on ajv@^6. Packages that a project lists in peerDependencies still follow the versions other projects use. pnpm dedupe and installs with autoDedupe: true still pick one version that satisfies every range. Set autoDedupe: true if CI runs pnpm dedupe --check #17235.

  • An optional dependency written with a named-registry prefix, such as work:^1.0.0, now fails the install when it cannot be resolved but the lockfile already has a matching entry from that registry....

Read more