pnpm, the JavaScript package manager, has replaced its previous TypeScript-and-Node.js implementation with Rust. pnpm 12, which reached stable status on August 26, 2026, carries over commands, configuration, and pnpm-lock.yaml from pnpm 11, and is designed not to require a major migration from users. That said, the speedup ranges from about 44% to about 97% depending on cache state. Compatibility fixes have continued even after the stable release, so rather than relying on the explanation "it's faster because it's Rust," adopters need to determine which tasks actually get faster and which existing commands to test.
From experimental backend to stable release in four months
The Rust implementation didn't replace all of pnpm from the start. A roadmap published on April 25, 2026 placed at Stage 1 a "headless installer" that reads an existing pnpm-lock.yaml and builds node_modules without newly resolving dependencies. This split kept dependency resolution in the existing pnpm codebase while the Rust side focused on fetching and placing packages. Moving resolution itself to Rust was planned for Stage 2.
With pnpm 11.2 on May 20, experimentation using this boundary began. Adding @pnpm/pacquet to the configuration let pnpm resolve dependencies and write the lockfile, while pacquet, the Rust implementation, fetched and placed the files. Because the existing lockfile served as the contract between the two implementations, the parts meant to speed things up and the parts meant to preserve compatibility could be tested separately.
The first pnpm 12 release candidate came out on August 5. The stable release followed 21 days later. In roughly four months from the April staged roadmap, the experimental backend responsible for fetching and placement expanded into pnpm 12, which now handles everything from dependency resolution to command execution. However, the identifier "pacquet" remains inside the repository, while the commands users run and the published product name stay "pnpm."
15ms repeat runs and a 4.29-second fresh install
An official benchmark dated September 4, 2026 compares pnpm 11.25.0 and pnpm 12.3.2. The published figures are the fastest of the three most recent runs, with each tool connecting to the same registry under conditions capped at 50ms latency and 200Mbps bandwidth. The fixtures split into alotta-files, which contains a large number of small files, and alotta-packages, which forms about 1GB of dependencies across 14 different tools. The absolute times between the two fixtures should not be compared directly; what matters is the generational difference within the same fixture.
| Condition | Fixture | pnpm 11 | pnpm 12 | Time reduction |
|---|---|---|---|---|
| Fresh install, no cache or lockfile | alotta-files | 7.67s | 4.29s | 44.1% |
| Repeat run, no changes | alotta-files | 469ms | 15ms | 96.8% |
| Dependency update | alotta-files | 3.54s | 1.00s | 71.8% |
| Fresh install, no cache or lockfile | alotta-packages | 24.3s | 13.6s | 44.0% |
| Repeat run, no changes | alotta-packages | 457ms | 18ms | 96.1% |
| Dependency update | alotta-packages | 12.0s | 3.34s | 72.2% |
The reduction rates in the table are calculated for each row as (pnpm 11 time − pnpm 12 time) ÷ pnpm 11 time. The reduction for fresh installs is around 44%; for dependency updates it widens to about 72%; and for repeat runs with no changes it reaches roughly 96-97%. In that last condition, the cache, lockfile, and node_modules all already exist. pnpm 12's 15-18ms figures are not the time for an initial setup, but the time for running the same operation again in the same working environment without changing dependencies.
Vercel's Turborepo migration measured the speed difference in a separate large-scale workspace. The target was 21 projects and 1,670 packages, with pnpm 10.28.0 and 12.0.0 each run 20 times on Linux x86_64 over XFS. Across the medians of four order-randomized blocks, the reduction rates across six conditions ranged from 64.4% to 90.5%. Runs where node_modules already existed dropped from 1.476 seconds to 142ms, while runs starting with no store and no node_modules, including running lifecycle scripts, dropped from 9.850 seconds to 3.472 seconds.
On the other hand, the Corepack download, which now includes a native executable, grew from 17.5MB to 47.3MB. In Vercel's measurements, startup with an empty Corepack cache slowed by 11.1%, from 711ms to 789ms, while startup with a cached download sped up by 74.7%, from 261ms to 66.8ms. Allocated capacity for the pnpm store and node_modules also fell by 52.5%, from 3.891GB to 1.850GB, though this result on XFS accounts for hard links. Repeat-run speed, initial fetch time, and disk usage should each be judged as separate conditions.
Dropping the Node.js dependency and changing how lockfiles are built
pnpm's basic design hasn't changed since before the Rust rewrite. Package contents are stored in a content-addressable store, and placed into each project's node_modules via hard links or copy-on-write. Not storing duplicate copies of the same file across projects has long supported both disk efficiency and strict dependency isolation. pnpm 12 keeps this placement model while moving dependency resolution and file handling to a native executable.
One likely reason the difference is so large for unchanged repeat runs is the weight of fixed costs. In scenarios without network transfer, the proportion of processing time taken up by JavaScript runtime startup, state reads, and link verification relatively increases. Going native can shorten this path, but the official benchmark is not a causal analysis based on CPU profiling. Because pnpm 12 also includes algorithmic and file-placement changes, the roughly 97% reduction cannot be attributed to Rust alone.
A representative example is how circular dependency graphs are handled. pnpm 12 sorts by package ID and fixes the point at which cycles are broken. Given the same dependency graph, it now produces a byte-identical lockfile regardless of ordering or traversal order within a workspace. In the official benchmark, peer dependency resolution in large workspaces with many cycles was 2-3 times faster, with memory usage down by about 25%. Existing lockfiles still work, but the first install that triggers re-resolution will produce a one-time change.
How far does "no migration needed" really hold?
Before releasing the stable version, the pnpm team validated the Rust rewrite against 10 large public workspaces, including n8n, Next.js, and Vite. The process covered fresh and repeat installs using a frozen lockfile, lockfile regeneration, and each repository's build, lint, and test steps. All 10 are recorded as having passed the main steps on at least one OS. Vercel's Turborepo migration was also merged on August 29, so there's now solid evidence that pnpm 12 works in real projects.
Even so, the promise of "carrying over pnpm 11's flags" required fixes. A PR merged on August 28 addressed an issue where the Rust version's argument parser was rejecting 16 configuration flags that pnpm 11 had accepted. These included --package-import-method and --child-concurrency, and the fix aligned both the presence/absence of values and their position on the command line with pnpm 11.
In 12.3.4 on September 4, boolean configuration flags such as --unsafe-perm, --offline, and --dangerously-allow-all-builds were also fixed. Because Vercel's build uses pnpm install --unsafe-perm, every install under the pre-fix version of pnpm 12 had been stopped by an argument error. Passing validation on public repositories doesn't fully cover organization-specific CI arguments.
Having a compatible lockfile is a different matter from every command working with the same meaning. pnpm install --resolution-only has been removed, with peer dependency checks moved to pnpm peers check. Git dependencies from GitHub, GitLab, and Bitbucket now go into the lockfile as normalized HTTPS URLs, meaning that fetching private repositories over SSH requires a URL-rewriting configuration on the Git side. Existing CI pipelines should fix their configuration files and actual command sequences in place before testing pnpm 12.
A gap between stable status and default distribution
Although pnpm 12 is stable, as of September 5, 2026 the npm latest tag still points to pnpm 11. Users on pnpm 11.10.0 or later can switch over with pnpm self-update next-12. Homebrew, winget, Scoop, and Chocolatey do not yet offer pnpm 12. The designation of stability and the timing of becoming the default across wider distribution channels remain separate.
Node.js requirements also differ depending on the installation route. The installation process using npx get-pnpm next-12 requires Node.js 22.13 or later, but once installed, pnpm 12 runs as a native executable and works without Node.js. With the standalone script, Node.js isn't needed even at install time. The Intel Mac executable, which didn't work with pnpm 11's standalone version, has also been restored.
Basing an adoption decision solely on the maximum reduction rate risks overlooking the slower initial Corepack fetch and differences in CLI arguments. The first step is to pin the pnpm version in CI to 12.3.4 or later, and run the usual install, update, and pre-publish checks with the same arguments. If those pass and the speedup holds up in cached, repeated work, the Rust rewrite can reliably cut the waiting time developers pay multiple times a day.
