Skip to content

build: update pnpm to v11#284

Open
angular-robot wants to merge 1 commit into
angular:mainfrom
angular-robot:ng-renovate/pnpm-11-x
Open

build: update pnpm to v11#284
angular-robot wants to merge 1 commit into
angular:mainfrom
angular-robot:ng-renovate/pnpm-11-x

Conversation

@angular-robot
Copy link
Copy Markdown
Contributor

@angular-robot angular-robot commented May 8, 2026

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
pnpm (source) 10.33.011.2.2 age adoption passing confidence

  • If you want to rebase/retry this PR, check this box

Release Notes

pnpm/pnpm (pnpm)

v11.2.2

Compare Source

Patch Changes
  • When the install engine is delegated to pacquet via configDependencies, the user's CLI flags passed to pnpm install (e.g. --no-runtime, --prod, --dev, --no-optional, --node-linker, --cpu/--os/--libc, --offline, --prefer-offline) are now forwarded to pacquet's install subcommand verbatim. Previously pacquet was invoked with a fixed argument list, so flags like --no-runtime were silently dropped. Flag forwarding is gated on the command being install/i; add, update, and dedupe still don't forward (their flag surface doesn't line up with pacquet's install).
  • Fixed pnpm up (and pnpm add / pnpm remove) failing with pacquet_package_manager::outdated_lockfile when pacquet is declared in configDependencies. pnpm now passes --ignore-manifest-check to pacquet so its --frozen-lockfile check doesn't fire against the (pre-mutation) package.json pnpm hasn't written yet #​11797. Requires a pacquet release that supports the flag — bump PACQUET_VERSION in the e2e tests once it ships.

v11.2.1

Compare Source

Patch Changes
  • Mark optional subdependency snapshots of config dependencies with optional: true in the env lockfile, matching how optional dependencies are recorded elsewhere in pnpm-lock.yaml. Previously, snapshots for the platform-specific subdeps pulled in via a config dep's optionalDependencies were written as empty objects, which was inconsistent with the rest of the lockfile and made it look like those non-host platform variants were required.
  • Fix pickRegistryForPackage returning the wrong registry for an unscoped npm: alias under a scoped local name. A manifest entry like "@​private/foo": "npm:lodash@^1" was routing the lodash fetch through registries["@​private"], even though lodash is unscoped and doesn't live on that registry. The npm-alias branch now returns the alias target's own scope (or null for an unscoped target, falling through to registries.default) instead of leaking into the local key's scope.
  • Don't print "Installing config dependencies..." when config dependencies are already installed and nothing needs to be fetched, re-linked, or removed.

v11.2.0

Compare Source

Minor Changes
  • Experimental: Adding @pnpm/pacquet (the Rust port of pnpm) to configDependencies in pnpm-workspace.yaml now delegates the materialization phase of pnpm install to the pacquet binary. pnpm still owns dependency resolution; pacquet only fetches and imports from the freshly-written lockfile. This is an opt-in preview of the Rust install engine #​11723.

    To configure pacquet in a project, run:

    pnpm add @​pnpm/pacquet --config
    

    You'll see changes in pnpm-workspace.yaml and pnpm-lock.yaml that should be committed. If you experience any issues with pacquet, please let us know by mentioning this in the GitHub issue you create.

  • configDependencies now resolve and install one level of optionalDependencies declared by the config dependency, with os/cpu/libc platform filtering applied at install time. This unlocks the esbuild/swc-style pattern where a package ships platform-specific binaries via optionalDependencies — a config dependency can now do the same and have the matching binary symlinked next to it in the global virtual store, so require('pkg-platform-arch') from inside the config dependency resolves correctly.

    The env lockfile records all platform variants regardless of host platform, so it remains portable across machines. Each entry in a config dependency's optionalDependencies must declare an exact version — ranges and tags are rejected to keep installs reproducible.

  • Implement the documented pnpm login --scope <scope> flag. The scope is normalized (a leading @ is added if missing; blank values are ignored) and an @<scope>:registry=<registry> mapping is written to the pnpm auth file alongside the auth token. Subsequent installs of @<scope>/* packages then route to the chosen registry. Previously pnpm login --scope foo errored with Unknown option: 'scope' despite the flag being listed in the online documentation #​11716.

  • pnpm outdated and pnpm update --interactive now report Node.js, Deno, and Bun runtimes installed as project dependencies (runtime: specifiers). Previously these were silently skipped.

Patch Changes
  • Fix cafile=<relative-path> in .npmrc being read from the wrong directory when pnpm is invoked from a different cwd (e.g. pnpm --dir <project> install from a CI wrapper or monorepo script). The path is now resolved against the directory of the .npmrc that declared it, not process.cwd(). Before this fix the CA file silently failed to load — the install proceeded without the configured CA and the user only saw TLS errors against a private registry, with no log line tying back to the wrongly resolved path #​11624.

  • Fix config.registry getting a trailing slash appended when registry is set in .npmrc and no registries.default is provided by pnpm-workspace.yaml. The sync from registries.default to config.registry introduced in #​11744 now only fires when the workspace manifest actually contributes a different default.

  • Fix global add/update to handle minimumReleaseAge policy violations instead of surfacing an internal resolver guardrail error.

  • Fix two crashes with injectWorkspacePackages: true when the lockfile has been pruned (e.g. by turbo prune --docker):

    • Cannot use 'in' operator to search for 'directory' in undefined: a peer-dependency-variant injected snapshot inherits its resolution from the base packages: entry; when a pruner drops that base entry the readers crash. convertToLockfileObject now reconstructs the directory resolution from the file: depPath at load time — a single normalization point, so every reader sees a fully-formed snapshot.
    • ERR_PNPM_ENOENT on node_modules/.bin/<tool>: after prepare/postinstall, runLifecycleHooksConcurrently re-imported each injected workspace package; the scanDir-into-filesMap workaround fed target-internal paths to the importer, which the makeEmptyDir fast path (#​11088) then wiped. Drop the workaround and pass keepModulesDir: true so the importer preserves the target's existing node_modules (bin links + transitive deps) and source files keep their hardlinks.
  • Fixed pnpm login and pnpm logout ignoring registries.default from pnpm-workspace.yaml #​10099.

  • Fix the minimumReleaseAge (publishedBy) maturity shortcut to be inclusive at the cutoff. Previously, abbreviated metadata whose modified field equalled the cutoff fell off the fast path and triggered a full-metadata re-fetch (or a MISSING_TIME error when full metadata wasn't permitted). Since modified is an upper bound on every version's publish time, modified == publishedBy already implies every version passes the per-version <= filter in filterPkgMetadataByPublishDate, so the shortcut now accepts the boundary case directly. Strictly > (was >=) at the rejection branch.

  • Honor publishConfig.access when publishing packages.

v11.1.3

Compare Source

Patch Changes
  • pnpm install now re-validates pnpm-lock.yaml entries against the active minimumReleaseAge and trustPolicy: 'no-downgrade' policies before any tarball is fetched. Lockfiles resolved elsewhere (committed to the repo, restored from a CI cache, produced by an older pnpm) under a weaker or absent policy can no longer install a freshly-published or trust-downgraded version silently. Violating entries abort the install with ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION, ERR_PNPM_TRUST_DOWNGRADE, or the generic ERR_PNPM_LOCKFILE_RESOLUTION_VERIFICATION when both policies trip in the same batch; minimumReleaseAgeExclude and trustPolicyExclude are honored. Verification results are cached so repeat installs against an unchanged lockfile take a fast path, and pnpm shows a transient progress line while the registry round-trip runs.

    When fresh resolution picks an immature version, the behavior depends on minimumReleaseAgeStrict:

    • Loose mode — the default, in effect whenever minimumReleaseAge keeps its built-in 24-hour value — auto-adds the immature picks to minimumReleaseAgeExclude in pnpm-workspace.yaml and lets the install proceed. A single info message lists what was persisted.
    • Strict mode in an interactive terminal collects every immature direct AND transitive pick in one pass and prompts once with the full list. Approving adds them to minimumReleaseAgeExclude and the install continues; declining aborts before the lockfile, package.json, or node_modules is touched.
    • Strict mode in CI (or any non-TTY context) aborts with ERR_PNPM_NO_MATURE_MATCHING_VERSION listing every offending entry, instead of failing on the first one the resolver hit.

    minimumReleaseAgeStrict auto-enables whenever the user explicitly sets minimumReleaseAge (CLI flag, env var, global config.yaml, or pnpm-workspace.yaml); set minimumReleaseAgeStrict: false to keep loose-mode auto-collect even with an explicit minimumReleaseAge value. Closes #​10438, #​10488, #​11687.

  • Allow redundant trailing base64 padding in .npmrc auth values and report invalid auth base64 with a pnpm error.

  • Make pnpm self-update respect minimumReleaseAge (and minimumReleaseAgeExclude) when resolving which pnpm version to install.

    When the latest dist-tag points to a version newer than the configured age threshold, self-update now selects the newest mature version instead unless excluded by minimumReleaseAgeExclude.

    Also makes dlx and outdated surface invalid minimumReleaseAgeExclude patterns under the same ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE error code already used by install, instead of leaking the internal ERR_PNPM_INVALID_VERSION_UNION / ERR_PNPM_NAME_PATTERN_IN_VERSION_UNION codes.

  • Global installs respect global config build policy (e.g., dangerouslyAllowAllBuilds from config.yaml) when GVS is enabled #​9249.

    The global virtual-store (GVS) default allowBuilds = {} was applied before workspace manifest settings were read and before global config values (stripped by extractAndRemoveDependencyBuildOptions) were re-applied via globalDepsBuildConfig. This caused hasDependencyBuildOptions to return true (because {} is not null), blocking restoration of global config values like dangerouslyAllowAllBuilds. As a result, global installs skipped all build scripts even when the config explicitly allowed them.

    This fix moves the GVS default to after workspace manifest reading and globalDepsBuildConfig re-application, so that:

    1. Workspace manifest allowBuilds takes precedence (if present)
    2. Global config dangerouslyAllowAllBuilds is properly restored (if set and no workspace policy exists)
    3. Empty {} is only applied as a last resort when no policy is configured anywhere
  • Honor --silent when verifyDepsBeforeRun: install auto-installs dependencies before pnpm run or pnpm exec, preventing install output from being written to stdout #​11636.

  • Fix lockfile parsing failures when pnpm-lock.yaml contains CRLF line endings and multiple YAML documents #​11612.

  • Anchor the side-effects-cache key and global-virtual-store hash to the project's script-runner Node — engines.runtime pin when present, shell node otherwise — instead of pnpm's own runtime.

    ENGINE_NAME (the <platform>;<arch>;node<major> prefix used as the side-effects-cache key and the engine portion of the GVS hash) was computed from process.version — the Node that runs pnpm itself. That was wrong in two situations:

    1. @pnpm/exe SEA bundle. The bundle has its own embedded Node, not the node on the user's PATH that actually spawns lifecycle scripts. Two pnpm installations on the same machine (one SEA, one npm-package) therefore disagreed on the cache key, partitioning the side-effects cache and the global virtual store across two Node majors even though both installs would run scripts on the same shell node.
    2. engines.runtime / devEngines.runtime pin. When a project pins a Node version via devEngines.runtime (pnpm v11+), pnpm downloads that Node into node_modules/node/ and uses it to run lifecycle scripts. But the hash still anchored to whichever Node ran pnpm itself, not to the pinned Node — so two installs of the same project with two different runner Nodes would still disagree on the GVS slot path even though scripts run on the same pinned Node.

    Three changes:

    • @pnpm/engine.runtime.system-node-version now exports engineName(nodeVersion?). Resolves the version in this order: explicit override → getSystemNodeVersion() (which already prefers node --version over process.version in SEA contexts) → process.version.
    • @pnpm/deps.graph-hasher now exports findRuntimeNodeVersion(snapshotKeys) — scans an iterable of lockfile snapshot keys for a node@runtime:<version> entry and returns its bare version string. calcDepState and calcGraphNodeHash/iterateHashedGraphNodes accept a nodeVersion? (in the options bag for the first, as a trailing parameter / ctx field for the others), forwarded to engineName(). The default (no override) preserves the pre-change behaviour. The legacy ENGINE_NAME constant in @pnpm/constants is unchanged so external consumers and existing tests keep working; in non-SEA, non-pinned contexts every value lines up.
    • Every install-side caller of the graph-hasher (@pnpm/installing.deps-resolver, @pnpm/installing.deps-restorer, @pnpm/installing.deps-installer, @pnpm/building.during-install, @pnpm/building.after-install, @pnpm/deps.graph-builder) now derives the project's pinned runtime via findRuntimeNodeVersion(Object.keys(graph)) once per invocation and threads it through.

    On upgrade, two one-time GVS slot churns are possible:

    • SEA-pnpm users without a runtime pin: slots that previously hashed under the embedded-Node major (e.g. node26) now hash under the shell-Node major (e.g. node24), matching what pacquet, the npm-published pnpm package, and any other pnpm-compatible tool already produce.
    • Projects with a devEngines.runtime pin: slots that previously hashed under the runner's Node major now hash under the pinned Node major, matching what the lifecycle scripts will actually run on.

    In both cases the old slots become prune-eligible.

  • Resolve the GVS hash's engine portion per-snapshot when a dependency declares its own engines.runtime, instead of using an install-wide value.

    Pnpm's resolver desugars a dep's engines.runtime into dependencies.node: 'runtime:<version>', and the bin linker spawns that dep's lifecycle scripts through the pinned Node downloaded into <pkgDir>/node_modules/node/. The GVS hash and the side-effects-cache key prefix were still anchored to the install-wide runtime — so a pinning snapshot's slot encoded the wrong Node major, and a reinstall on the same host could read the cached side-effects under a key whose <platform>;<arch>;node<major> triple disagreed with the Node the build actually ran on.

    Per-snapshot resolution now matches what bins/linker already does on a per-package basis:

    • @pnpm/deps.graph-hasher adds readSnapshotRuntimePin(children) — reads the node entry from one snapshot's graph children and extracts the version from a node@runtime: value. Pairs with the existing findRuntimeNodeVersion(snapshotKeys) install-wide fallback (also now exported from @pnpm/deps.graph-hasher rather than @pnpm/engine.runtime.system-node-version, where it was a poor fit — system-node-version is about probing the host Node, not parsing lockfile-derived strings).
    • calcDepState and calcGraphNodeHash consult readSnapshotRuntimePin(graph[depPath].children) first and only fall back to the install-wide nodeVersion parameter when the snapshot doesn't pin its own Node.

    Pacquet mirrors the same precedence at the calc_graph_node_hash call site in package-manager/src/virtual_store_layout.rs — a new find_own_runtime_node_major(snapshot) helper reads each snapshot's dependencies for a node entry with Prefix::Runtime and overrides the install-wide engine when present.

    On upgrade, snapshots of dependencies that declare their own engines.runtime re-hash under that dep's pinned Node instead of the install-wide value. The old slots become prune-eligible. Closes #​11690.

  • Fixed pnpm publish failing with a 404 when authentication relied on OIDC trusted publishing alongside an .npmrc written by actions/setup-node (_authToken=${NODE_AUTH_TOKEN}) without NODE_AUTH_TOKEN being set. Unresolved ${VAR} placeholders in auth values are now treated as empty rather than passed through verbatim, so the literal placeholder no longer surfaces as a bearer token when OIDC fallback is the intended auth source #​11513.

  • Fix devEngines.packageManager (singular form, without onFail) defaulting to onFail: "error" instead of the documented pmOnFail: "download". As a result, a project that pinned a different pnpm version via devEngines.packageManager and ran pnpm install from a mismatched pnpm version failed with a hard error, even though the migration table from managePackageManagerVersions: true to pmOnFail: download (default) promises the install would auto-download the wanted version #​11676.

    The array form of devEngines.packageManager keeps its existing per-element defaults (error for the last entry, ignore for the rest), since those reflect explicit prioritization by the user. Explicit onFail values continue to win.

  • Fix devEngines.packageManager not writing packageManagerDependencies to pnpm-lock.yaml when the lockfile lacks an env-doc entry. Previously the lockfile sync skipped resolution unless an existing packageManagerDependencies.pnpm entry needed refreshing, so a fresh install without onFail: "download" left the resolved pnpm version unrecorded — contradicting the documented behavior that the resolved version is stored in pnpm-lock.yaml #​11674.

  • Warn when package.json contains a legacy pnpm field with settings pnpm no longer reads from package.json (e.g. pnpm.overrides, pnpm.patchedDependencies). Previously these were silently ignored after the upgrade from v10, leaving users unaware that their overrides/patched dependencies had stopped taking effect #​11677.

v11.1.2

Compare Source

Patch Changes
  • convertEnginesRuntimeToDependencies: switch the runtime-dependency write to Object.defineProperty so the CodeQL js/prototype-polluting-assignment rule treats the assignment as safe regardless of the property name (follow-up to #​11609).

  • Address CodeQL static-analysis findings: guard manifest dependenc

Note

PR body was truncated to here.


Configuration

  • Added support for a global YAML config file named config.yaml.

    Configuration is now split into two categories:

    • Registry and auth settings, which can be stored in INI files such as the global rc file and local .npmrc.
    • pnpm-specific settings, which can only be loaded from YAML files such as the global config.yaml and local pnpm-workspace.yaml.
  • Added support for loading environment variables whose names start with pnpm_config_ into config. These environment variables override settings from pnpm-workspace.yaml but not CLI arguments.

  • Added support for reading allowBuilds from pnpm-workspace.yaml in the global package directory for global installs.

  • Added support for pnpm config get globalconfig to retrieve the global config file path #​9977.

  • Added a new setting virtualStoreOnly that populates the virtual store without creating importer symlinks, hoisting, bin links, or running lifecycle scripts. This is useful for pre-populating a store (e.g., in Nix builds) without creating unnecessary project-level artifacts. pnpm fetch now uses this mode internally #​10840.

  • Added support for specifying the pnpm version via devEngines.packageManager in package.json. Unlike the packageManager field, this supports version ranges. The resolved version is stored in pnpm-lock.yaml and reused if it still satisfies the range #​10932.

  • Added a new dedupePeers setting that reduces peer dependency duplication. When enabled, peer dependency suffixes use version-only identifiers (name@version) instead of full dep paths, eliminating nested suffixes like (foo@1.0.0(bar@2.0.0)). This dramatically reduces the number of package instances in projects with many recursive peer dependencies #​11070.

  • Config dependencies are now installed into the global virtual store ({storeDir}/links/) and symlinked into node_modules/.pnpm-config/. This allows config dependencies to be shared across projects that use the same store, avoiding redundant fetches and imports #​10910. Config dependency and package manager integrity info is now stored in pnpm-lock.yaml instead of inlined in pnpm-workspace.yaml: the workspace manifest contains only clean version specifiers for configDependencies, while the resolved versions, integrity hashes, and tarball URLs are recorded in the lockfile as a separate YAML document. The env lockfile section also stores packageManagerDependencies resolved during version switching and self-update. Projects using the old inline-hash format are automatically migrated on install #​10912 #​10964.

  • Added nodeDownloadMirrors setting to configure custom Node.js download mirrors in pnpm-workspace.yaml. This replaces the node-mirror:<channel> .npmrc setting, which is no longer read #​11194:

    nodeDownloadMirrors:
      release: https://my-mirror.example.com/download/release/
  • pnpm dlx and pnpm create now respect security and trust policy settings (minimumReleaseAge, minimumReleaseAgeExclude, minimumReleaseAgeStrict, trustPolicy, trustPolicyExclude, trustPolicyIgnoreAfter) from project-level configuration #​11183.

  • pnpm init now writes a devEngines.packageManager field instead of the packageManager field when init-package-manager is enabled.

  • Added a new setting runtimeOnFail that overrides the onFail field of devEngines.runtime (and engines.runtime) in the root project's package.json. Accepted values: ignore, warn, error, download. For example, setting runtimeOnFail=download makes pnpm download the declared runtime version even when the manifest does not set onFail: "download".

  • Added a new setting minimumReleaseAgeIgnoreMissingTime, which is true by default. When enabled, pnpm skips the minimumReleaseAge maturity check if the registry metadata does not include the time field. Set to false to fail resolution instead.

Store
  • When the global virtual store is enabled, packages that are not allowed to build (and don't transitively depend on packages that are) now get hashes that don't include the engine name (platform, architecture, Node.js major version). This means ~95% of packages in the GVS survive Node.js upgrades and architecture changes without re-import #​10837.
Hooks & Pnpmfiles
  • Added support for pnpmfiles written in ESM, using the .mjs extension. When .pnpmfile.mjs exists, it takes priority over .pnpmfile.cjs and only one is loaded #​9730.
CLI & Other
  • The built-in clean, setup, deploy, and rebuild commands now prefer user scripts over built-in commands. When a project's package.json has a script with the same name, pnpm executes the script instead of the built-in command. Added purge as an alias for the built-in clean command, which always runs the built-in regardless of scripts #​11118.
  • Added -F as a short alias for the --filter option.
  • Added support for hidden scripts. Scripts starting with . are hidden and cannot be run directly via pnpm run. They can only be called from other scripts. Hidden scripts are also omitted from the pnpm run listing #​11041.
  • pnpm approve-builds now accepts positional arguments for approving or denying packages without the interactive prompt. Prefix a package name with ! to deny it. Only mentioned packages are affected; the rest are left untouched #​11030.
  • During install, packages with ignored builds that are not yet listed in allowBuilds are automatically added to pnpm-workspace.yaml with a placeholder value, so users can manually set them to true or false #​11030.
  • Added pn and pnx short aliases for pnpm and pnpx (pnpm dlx) #​11052.
  • pnpm store prune now displays the total size of removed files #​11047.
  • pnpm audit --fix now adds the minimum patched version for each advisory to minimumReleaseAgeExclude in pnpm-workspace.yaml, so the security fix can be installed without waiting for minimumReleaseAge #​11216.
  • pnpm now warns when optimisticRepeatInstall skips shouldRefreshResolution hooks #​10995.
Performance
  • Replaced node-fetch with native undici for HTTP requests throughout pnpm #​10537.
  • Eliminated redundant internal linking during GVS warm reinstall when no packages were added #​11073.
  • Eliminated the staging directory when importing packages into node_modules, avoiding the overhead of creating a temp dir and renaming per package #​11088.
  • CAS files are now written directly to their final content-addressed path instead of to a temp file and renamed. This eliminates ~30k rename syscalls per cold install #​11087.
  • Optimized hot-path string operations in the content-addressable store and increased gunzipSync chunk size for fewer buffer allocations during tarball decompression #​11086.
  • Improved HTTP performance with Happy Eyeballs (dual-stack), better keep-alive settings, and an optimized global dispatcher. Tarball downloads with known size now pre-allocate memory to avoid double-copy overhead #​11151.
  • Adopted If-Modified-Since for conditional metadata fetches, avoiding re-downloading unchanged registry metadata #​11161.
  • Switched to abbreviated metadata when checking minimumReleaseAge, reducing the amount of data fetched from the registry #​11160.
  • Switched the metadata cache to NDJSON format, improving read/write performance #​11188.
Patch Changes
  • Switched to process.stderr.write instead of console.error for script logging #​11140.

  • Respected the frozen-lockfile flag when migrating config dependencies #​11067.

  • Removed the --workspace flag from the version command #​11115.

  • Handled ENOTSUP error in the clone import path during parallel I/O #​11117.

  • Fixed pnpm audit command.

  • Updated dependencies to fix vulnerabilities.

  • pnpm now checks whether a package is installable for non-npm-hosted packages (e.g., git or tarball dependencies) after the manifest has been fetched.

  • pnpm now explicitly passes the path of the global rc config file to npm.

  • Fixed YAML formatting preservation in pnpm-workspace.yaml when running commands like pnpm update. Previously, quotes and other formatting were lost even when catalog values didn't change.

    Closes #​10425

  • The parameter set by the --allow-build flag is now written to allowBuilds.

  • Fixed a bug in which specifying filter in pnpm-workspace.yaml would cause pnpm to not detect any projects.

  • Deferred patch errors until all patches in a group are applied, so that one failed patch does not prevent other patches from being attempted.

  • pnpm now fails on incompatible lockfiles in CI when frozen lockfile mode is enabled #​10978.

  • Fixed strictDepBuilds and allowBuilds checks being bypassed when a package's build side-effects are cached in the store #​11039.

  • In GVS mode, pnpm approve-builds now runs a full install instead of rebuild, ensuring that GVS hash directories and symlinks are updated correctly after changing allowBuilds #​11043.

  • Fixed a crash in the lockfile merger when merging non-semver version strings (e.g. link:, file:, git URLs) #​11102.

  • Handled ENOTSUP error in linkOrCopy during parallel imports #​11103.

  • Skipped linking bins that already reference the correct target. This avoids redundant I/O during repeated installs and prevents permission errors when the store is read-only (e.g. Docker layer caching, CI prewarm, NFS) #​11069.

  • Fixed _password handling for the default registry to decode from base64 before use, consistent with scoped registry behavior #​11089.

  • Fixed a bug where the CAS locker cache was not updated when a file already existed with correct integrity #​11085.

  • Prevented catalog entries from being removed by cleanupUnusedCatalogs when they are referenced only from workspace overrides #​11075.

  • Resolved patch file paths during pnpm fetch #​11054.

  • Fixed invalid specifiers for peers on all non-exact version selectors #​11049.

  • Fixed false "Command not found" error on Windows when the command exists but exits with a non-zero exit code #​11000.

  • Prepended Bearer to the authorization token generated by tokenHelper if it is missing, aligning with npm's behavior #​11097.

  • Propagated error cause when throwing PnpmError in @pnpm/npm-resolver #​10990.

  • Fixed SQLite race condition during store initialization on Windows.

  • Removed rimrafSync in importIndexedDir fast-path error handler #​11168.

  • Fixed pnpm dedupe --check unexpectedly failing due to non-deterministic resolution #​11110.

  • Fixed empty files not being rejected in isEmptyDirOrNothing #​11182.

  • Fixed .bat/.cmd token helpers not working on Windows due to missing shell: true option.

v10.33.4: pnpm 10.33.4

Compare Source

Patch Changes
  • Pin the integrity of git-hosted tarballs (codeload.github.com, gitlab.com, bitbucket.org) in the lockfile so that subsequent installs detect a tampered or substituted tarball and refuse to install it. Previously the lockfile only stored the tarball URL for git dependencies, so a compromised git host or a man-in-the-middle could serve arbitrary code on later installs without lockfile changes.

    A new gitHosted: true field is recorded on git-hosted tarball resolutions in the lockfile, letting every reader/writer route them by a single typed check instead of pattern-matching the tarball URL in each call site. Lockfiles written by older pnpm versions are enriched on load (URL fallback) so the field can be relied on uniformly across the codebase.

  • Fix a regression where pnpm --recursive --filter '!<pkg>' run/exec/test/add would include the workspace root in the matched projects. The workspace root is now correctly excluded by default when only negative --filter arguments are provided, matching the documented behavior. To include the root, pass --include-workspace-root #​11341.

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

v10.33.3: pnpm 10.33.3

Compare Source

Patch Changes
  • When self-updating from v10's @pnpm/exe to v11+ on Intel macOS (darwin-x64), pnpm self-update now transparently switches to the JS-only pnpm package on npm instead of installing @pnpm/exe@v11+ (which doesn't ship a working binary for Intel Macs because of an upstream Node.js SEA bug — see #​11423 and nodejs/node#62893). Without this, the self-update would silently leave the user with no working pnpm binary. The new install requires Node.js to be available on PATH; a warning is printed when the swap happens. All other host/version combinations are unchanged.
  • pnpm self-update (with no version argument) no longer downgrades pnpm when the registry's latest dist-tag points to an older release than the currently active version. Run pnpm self-update latest to force a downgrade #​11418.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

v10.33.2: pnpm 10.33.2

Compare Source

Patch Changes
  • Globally-installed bins no longer fail with ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND when pnpm was installed via the standalone @pnpm/exe binary (e.g. curl -fsSL https://get.pnpm.io/install.sh | sh -) on a system without a separate Node.js installation. Previously, when which('node') failed during pnpm add --global, pnpm fell back to process.execPath, which in @pnpm/exe is the pnpm binary itself — and that path was baked into the generated bin shim, causing the shim to invoke pnpm instead of Node #​11291, #​4645.

  • Fix an infinite fork-bomb that could happen when pnpm was installed with one version (e.g. npm install -g pnpm@A) and run inside a project whose package.json selected a different pnpm version via the packageManager field (e.g. pnpm@B), while a pnpm-workspace.yaml also existed at the project root.

    The child's environment is now forced to manage-package-manager-versions=false (v10) and pm-on-fail=ignore (v11+), which disables the package-manager-version handling in whichever pnpm runs as the child.

    Fixes #​11337.

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

v10.33.1: pnpm 10.33.1

Compare Source

Patch Changes
  • When a project's packageManager field selects pnpm v11 or newer, commands that v10 would have passed through to npm (version, login, logout, publish, unpublish, deprecate, dist-tag, docs, ping, search, star, stars, unstar, whoami, etc.) are now handed over to the wanted pnpm, which implements them natively. Previously they silently shelled out to npm — making, for example, pnpm version --help print npm's help on a project with packageManager: pnpm@11.0.0-rc.3 #​11328.
Platinum Sponsors
Bit
Gold Sponsors
Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

@angular-robot angular-robot force-pushed the ng-renovate/pnpm-11-x branch 4 times, most recently from 6e89300 to 5805a29 Compare May 13, 2026 11:19
@angular-robot angular-robot force-pushed the ng-renovate/pnpm-11-x branch 3 times, most recently from 83250cd to 20319a6 Compare May 21, 2026 17:23
See associated pull request for more information.
@angular-robot angular-robot force-pushed the ng-renovate/pnpm-11-x branch from 20319a6 to 5edb81b Compare May 22, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant