pnpm v12 Ships the Rust Rewrite

Updated

pnpm v12 rewritten in Rust: the pnpm logo, a heart, and the Rust logo side by side

Every package manager has a moment where you just wait. You add one dependency, or you pull a branch and run install, and there’s a beat where the terminal sits there doing file I/O while you tab away. pnpm already made that beat shorter than most, staying ahead of npm and Yarn on most install scenarios thanks to its content-addressable store and hard-linked node_modules. But it was still a Node.js program, paying the Node startup cost and pushing tens of thousands of file operations through a single JavaScript runtime.

That is what changes in pnpm v12: it rewrites the install engine, the part that fetches and links packages, in Rust, and leaves the CLI, lockfile, and node_modules layout untouched. It’s the same move TypeScript just made with Go, aimed at a different bottleneck. And like that one, the interesting detail is how little actually changes for you.

What pnpm v12 actually is

pnpm v12 is the same pnpm you already use, ported to Rust. pnpm has always been TypeScript running on Node.js, and the Rust work lives under the codename pacquet, whose repo describes it in one line: “The official pnpm rewrite in Rust.” The key word there is rewrite, not reimagining. It’s a port. The flags, defaults, error codes, lockfile format, and node_modules layout are all meant to match pnpm exactly.

Zoltan Kochan, pnpm’s creator, put it plainly when the v12 plan came together: “v12 should behave the same as v11, the biggest change will be the full rewrite to Rust.” That’s the frame to hold onto. This is a performance release wearing a major version number, not a redesign of how pnpm works.

pacquet started as a separate experimental repo and moved into the main pnpm monorepo in May 2026, so the TypeScript and Rust versions now evolve side by side. The eventual goal is for the Rust engine to be what you run.

Why did pnpm choose Rust?

The motivation isn’t abstract. Two things were capping how fast a Node-based pnpm could go.

The first is startup cost. Every invocation booted a Node.js runtime before it did any work. pnpm v12 ships as native per-platform binaries with no Node.js launcher, so a command pays no runtime bootstrap cost at all. On a fast, cached install where the actual work is milliseconds, that bootstrap was a real fraction of the wall-clock time.

The second is the file I/O itself. A cold install on a large monorepo is really a lot of filesystem operations: fetching tarballs, unpacking them into the store, and hard-linking thousands of files into place. Running all of that through a single JavaScript thread leaves throughput on the table. Rust handles that fan-out natively, without the runtime sitting in the middle of every syscall.

There’s a softer reason too, and it’s the same one that’s driving the broader trend: the tooling to do this kind of rewrite has gotten dramatically better, and AI-assisted porting made a 1:1 translation of a large codebase far more tractable than it would have been a few years ago.

How much faster is pnpm v12?

pnpm publishes a benchmark suite comparing v11 against the Rust engine directly, and it re-runs weekly, so the exact figures move. As of late August 2026, here’s what it shows:

Scenario pnpm v11 pnpm (Rust)
Everything warm (repeat install) 472 ms 15 ms
node_modules present, no cache 580 ms 67 ms
Clean install (nothing cached) 8.2 s 5 s

The warm case is everything already in place, so the install just re-verifies the tree, which is what happens on every CI job. That drops from 472ms to 15ms, roughly a 30x difference, and it’s the number you’ll feel most, because it runs constantly. The colder cases improve less dramatically: a fully clean install with nothing cached goes from 8.2s to 5s, about 1.6x, since the wall-clock time there is dominated by network and tarball unpacking rather than the engine.

Treat these as pnpm’s own numbers on pnpm’s own hardware, and expect your mileage to vary with disk speed and project size. But the direction is not subtle, and the team’s claim is that the Rust engine is faster than v11 in every scenario they measured.

It’s already rolling out, incrementally

Here’s the part that’s easy to get wrong: pnpm v12 isn’t a big-bang release. The Rust engine has been landing piece by piece through the v11 line, opt-in first.

  • pnpm 11.2 let you opt into pacquet as the install backend for materialization only. Rust did the fetch and link, while pnpm still resolved dependencies and wrote the lockfile.
  • pnpm 11.7 went further: a standard install could be delegated to pacquet end-to-end, with resolution, lockfile write, and linking all in a single Rust pass.
  • pnpm 11.10 added pnpm self-update next-12, so you can pull the v12 line and try the Rust binary directly.

In v12, the Rust engine for fetching and linking is the default rather than an opt-in. The roadmap works outward from there: first the headless frozen-lockfile installer, then full dependency resolution (add, update, remove, catalogs, overrides, peers), and finally the remaining commands like run, store, and publish. So even in v12, parts of pnpm still run through the TypeScript implementation for now. The lockfile is what lets the two halves cooperate.

What changes for you?

The honest answer is: not much, on purpose. Same CLI, same lockfile, same node_modules. The whole point of a 1:1 port is that your muscle memory and your CI scripts keep working.

The breaking changes that shipped are narrow, and most are about correctness rather than workflow. pnpm now treats a git dependency on a known host (GitHub, GitLab, Bitbucket) as an identity rather than a transport choice, so the lockfile stops recording a machine-specific SSH URL that only worked wherever resolution happened to run. An unrecognized setting in pnpm-workspace.yaml is reported instead of silently ignored, and fails the command outright when your project pins a matching pnpm version. And dependency cycles are broken canonically, so repeated installs produce byte-identical lockfiles regardless of importer order. One more change touches the command line: --resolution-only is gone, and v12 rejects the flag outright. Its old job of printing peer-dependency issues now falls to pnpm peers check, which reads them straight from the lockfile without a reinstall or a re-resolution. If none of those touch your setup, a v12 upgrade should be close to a no-op.

Will the upgrade break your CI?

Probably not, but the one thing worth checking is feature parity during the transition. Because the Rust engine is being ported incrementally, some newer or niche capabilities may lag the TypeScript version at any given moment. If your install depends on something specific (a particular linker mode, lockfile-verification settings, or pnpm deploy), test the bump in an isolated git worktree before you flip it on in CI, the same sandbox I used while exploring SolidJS 2.0’s async data model. This is still moving, so the right list of gaps is whatever the release notes and roadmap say on the day you upgrade.

The bigger picture

pnpm is not doing this alone. The last few years have quietly rebuilt the JavaScript toolchain’s foundations in native languages: Biome for linting and formatting, Oxc for parsing and transforming, Rolldown and Turbopack for bundling, and now Astro 7 with its Rust compiler and Sätteri markdown pipeline. TypeScript’s compiler went to Go. Deno is Rust from the ground up. (Bun was the odd one out for a while, written in Zig, not Rust. That’s no longer true: it’s now rewriting itself from Zig to Rust too, an AI-assisted port I wrote up separately in Bun’s Rust rewrite.)

There’s a competitive angle underneath it, too. Bun and Deno both ship as single fast binaries with package management built in, and a chunk of their appeal is exactly that no-runtime-bootstrap speed. A native-binary pnpm with no Node launcher closes that gap while keeping the thing that makes pnpm pnpm: the strict, content-addressable store and the non-flat node_modules that catches phantom dependencies.

Should you upgrade to pnpm v12?

You can, and there’s little reason to hold off. pnpm v12.0.0 shipped stable on August 26, 2026, so the Rust engine is no longer an alpha you opt into on a branch. Run pnpm self-update to move onto it, or bump the packageManager pin in your repo, and your existing scripts keep working.

If you want to feel the difference before you commit the whole team, do a warm install on a throwaway branch and watch it return before you’ve finished reading the command. The type of release this is, where the language underneath gets an order of magnitude faster while everything on top stays exactly where you left it, is a rare and good one. pnpm was already the fast package manager. It’s no longer one you ever wait on.