Install Speed
Two projects installed six ways each — the cache and lockfile states you actually end up in, from a fresh clone to a warm re-run.
alotta-files
A wide dependency graph of small packages — lots of files to link, little to resolve.
Total across all scenarios
- pnpm 12 + pnpr9.14sfastest
- pnpm 12 + global store10.8s1.2x slower
- pnpm 1210.8s1.2x slower
- pnpm 12 hoisted11.9s1.3x slower
- pnpm 1125.0s2.7x slower
- npm1m 28s9.7x slower
All 6 scenarios added up.
Exact numbers
| Scenario | npmv12.0.2 | pnpm 11v11.25.0 | pnpm 12v12.3.1 | pnpm 12 + pnprv12.3.1 | pnpm 12 + global storev12.3.1 | pnpm 12 hoistedv12.3.1 |
|---|---|---|---|---|---|---|
| cleanA fresh clone. Nothing cached. | 47.8s | 8.25s | 4.97s | 3.38s | 5.28s | 4.97s |
| cacheReinstalling without a lockfile. | 13.4s | 4.67s | 952ms | 724ms | 706ms | 966ms |
| lockfileCI, first install. | 12.7s | 4.83s | 3.31s | 3.27s | 3.29s | 3.56s |
| cache + lockfileReinstalling a project you already have. | 8.61s | 2.44s | 595ms | 673ms | 393ms | 621ms |
| everything warmRunning install when nothing changed. | 1.32s | 594ms | 19ms | 20ms | 19ms | 19ms |
| updateA dependency was bumped in package.json. | 4.49s | 4.25s | 968ms | 1.06s | 1.08s | 1.72s |
alotta-packages
Fourteen modern toolchains — Angular, Nest, Vite, webpack, Storybook — resolving to about a gigabyte.
Total across all scenarios
- pnpm 12 + pnpr24.7sfastest
- pnpm 12 + global store30.5s1.2x slower
- pnpm 1232.4s1.3x slower
- pnpm 12 hoisted36.6s1.5x slower
- pnpm 111m 16s3.1x slower
- npm3m 49s9.3x slower
All 6 scenarios added up.
Exact numbers
| Scenario | npmv12.0.2 | pnpm 11v11.25.0 | pnpm 12v12.3.1 | pnpm 12 + pnprv12.3.1 | pnpm 12 + global storev12.3.1 | pnpm 12 hoistedv12.3.1 |
|---|---|---|---|---|---|---|
| cleanA fresh clone. Nothing cached. | 1m 49s | 25.2s | 15.0s | 9.01s | 15.2s | 15.0s |
| cacheReinstalling without a lockfile. | 42.0s | 17.8s | 3.15s | 2.28s | 1.98s | 3.07s |
| lockfileCI, first install. | 32.4s | 12.8s | 8.76s | 8.87s | 8.98s | 10.0s |
| cache + lockfileReinstalling a project you already have. | 24.5s | 5.53s | 2.13s | 2.10s | 973ms | 2.06s |
| everything warmRunning install when nothing changed. | 3.98s | 588ms | 22ms | 24ms | 21ms | 21ms |
| updateA dependency was bumped in package.json. | 16.6s | 14.4s | 3.26s | 2.38s | 3.30s | 6.45s |
- Two projects, run separately: "alotta-files" is a wide graph of small packages, "alotta-packages" is fourteen modern toolchains resolving to about a gigabyte. Both are shown because they do not agree — pnpm leads on each, but by different margins, and pnpr gains far more on the larger graph.
- Within a project the only thing that changes is the package manager, and every manager is measured with the same versions on both projects. Numbers are never combined across projects.
- Each number is the fastest of the three most recent runs.
- Everything installs through the same registry over the same emulated link (50ms, 200Mbps), so the times include the round trips a real install pays for.
- Six scenarios here. The suite measures three more that delete your cache or lockfile but keep node_modules — nobody works that way, so they are left out.
- pnpm 12 + pnpr is the same version and the same command, with resolution handled by the registry instead of locally.
- The three columns after pnpm 12 are that same pnpm 12 configured differently — a global virtual store, a hoisted node_modules, and registry-side resolution. They are shown to make the cost of each setting visible, and are left out of the headline numbers above, which describe pnpm as it installs by default.
Node.js Version Management
pnpm installs and switches Node.js versions itself, so you may not need a version manager at all. Here it is against fnm and nvm.
Total across all scenarios
- pnpm1.50sfastest
- fnm5.94s3.9x slower
- nvm6.12s4.1x slower
All 3 scenarios added up.
Exact numbers
| Scenario | pnpmv12.3.1 | fnmv1.39.0 | nvmv0.40.7 |
|---|---|---|---|
| install (clean)Install Node.js 24, nothing cached. | 1.35s | 2.98s | 3.15s |
| install (warm store)Install a version you had before. | 151ms | 2.95s | 2.88s |
| run in projectRun node in a project pinned to Node.js 22. | 7ms | 5ms | 93ms |
- pnpm keeps Node.js in its store, so a version it has seen before needs no download.
- There is no switch command — the node on your PATH is whatever the project asks for.
- Timed inside a shell with $EPOCHREALTIME, because nvm is a shell function rather than a binary.
How these numbers are produced
Every tool runs on the same machine against the same project, and the timings are committed to pnpm/benchmarks. This page reads them at build time and picks the newest version of each tool.
This is one project on one machine — your numbers will differ. Run pnpm run benchmark to see your own.