← ALL ARTICLES

27 SEP 2026 · 6 MIN READ

npm vs pnpm vs Bun: I Benchmarked All Three on My Own Project

Real install times, real disk usage, and a real build, measured on the React + Vite project behind this website. Plus the pnpm error that will catch you out after an upgrade.

Most "npm vs pnpm vs Bun" articles repeat each tool's marketing numbers. I wanted numbers from a project I actually ship, so I benchmarked all three on the codebase behind this website and measured what I care about day to day: install speed, disk space, and whether everything still works.

I've used all three on real projects, and Bun is my daily driver. Here's what the numbers say, and why Bun is the one I reach for.

The test setup

  • Project: this portfolio, React 19 + Vite 6 + TypeScript + Tailwind. 8 dependencies and 17 dev dependencies, which pull in 344 packages and about 19,000 files.
  • Tools: npm 10.8.2 (bundled with Node.js 20.19.4), pnpm 12.6.0, Bun 1.4.2 (used only as a package manager, not as the runtime).
  • Machine: my Linux server: 6 CPU cores, 11 GB RAM, datacenter internet.
  • Method: each tool got its own copy of the project and its own separate cache, so none could reuse another's downloads. Every test ran 3 times; I report the median.

I tested four situations you actually run into:

  1. First install: no cache, no lockfile. Like setting up a new project on a fresh machine.
  2. CI without a cache: a lockfile exists, but nothing is downloaded yet.
  3. Fresh clone: a lockfile and a warm cache, but no node_modules. Like cloning a project on a machine you've used before.
  4. Already installed: running install again when nothing changed.

Install speed

Scenario npm pnpm Bun
First install (no cache, no lockfile) 40.3 s 4.0 s 2.4 s
CI without a cache (lockfile only) 13.1 s 2.2 s 1.1 s
Fresh clone (lockfile + warm cache) 9.6 s 0.37 s 0.20 s
Already installed 0.87 s 0.02 s 0.02 s

Bun is the fastest in every scenario, but the bigger story is the gap between npm and the other two. On a first install, pnpm was 10× faster than npm and Bun was 17× faster. With a warm cache, both finish in well under half a second while npm still takes almost 10.

The difference between pnpm and Bun is real but small in practice: 4.0 s versus 2.4 s is not something I notice. The difference between either of them and npm's 40 seconds is.

Disk space: where it really adds up

Measured on its own, node_modules is about the same size with every tool: 208 MB for npm, 194 MB for pnpm, 209 MB for Bun. The difference shows up as soon as you have more than one project on the same machine.

Real disk used (cache + node_modules) npm pnpm Bun
1 project 243 MB 211 MB 217 MB
2 projects 450 MB 220 MB 221 MB
Cost of the second project 207 MB 9 MB 4 MB

npm gives every project its own full copy of every package. pnpm and Bun keep one copy of each file in a shared store and hard-link it into each project, so the same file on disk appears in many places at once. A second project with the same dependencies costs almost nothing.

Most comparisons credit only pnpm with this, but in my test Bun did the same thing on Linux: I checked, and its files were hard-linked from its cache too.

This matters on servers. On a VPS hosting several sites, that's the difference between gigabytes of duplicated node_modules and almost none.

Compatibility: does it all still build?

Speed doesn't matter if the project breaks. So after installing with each tool, I ran the full production build: TypeScript check, Vite build, and prerendering every page of this site.

All three passed, producing the same pages in roughly the same time (11 to 13 seconds). That makes sense, because the build runs on Node.js no matter which tool installed the packages.

But pnpm didn't pass on the first try.

The pnpm error that will catch you out

On every install, pnpm 12 stopped with this:

Ignored build scripts: [email protected]
Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
Error: ERR_PNPM_IGNORED_BUILDS

This is a security feature, not a bug. Recent versions of pnpm don't let dependencies run install scripts unless you approve them, because install scripts are a common way for malicious packages to attack your machine. In pnpm 12, an unapproved script now fails the whole install. esbuild is used by Vite, so almost every Vite project will hit this.

The fix is to approve the packages you trust in pnpm-workspace.yaml at the root of your project:

allowBuilds:
  esbuild: true

Or run pnpm approve-builds and pick them interactively. After that, installs ran cleanly.

npm runs every package's install scripts without asking, which is convenient but riskier. Bun sits in the middle: it only runs scripts for packages on its built-in trusted list (esbuild is on it) or ones you add to trustedDependencies in package.json, which is why Bun installed without complaint.

Monorepos

All three support workspaces, so you can have several apps and shared packages in one repository. pnpm's support is the most mature: pnpm-workspace.yaml plus the --filter flag make it easy to install, build, or test just one app and its dependencies. npm and Bun both handle workspaces through the workspaces field in package.json and are fine for simpler setups.

So which one do I use?

Bun, day to day. It won every speed test, used the least extra disk for a second project, and installed my Vite project with no extra configuration. Its trusted-list approach to install scripts is a good middle ground: well-known packages like esbuild just work, and anything else has to be explicitly trusted. And even when I only use it as a package manager, my build still runs on Node.js, so switching doesn't put my production setup at risk.

pnpm, for bigger monorepos, or when strict dependencies matter most. It's within a second or two of Bun, saves the same disk space, and has the most mature workspace tooling. It's also strict: a package can only import what it actually declares, which catches bugs that a flat node_modules quietly hides. Just remember the build-script approval when you upgrade.

npm, when zero setup matters. It ships with Node.js, every tutorial and hosting platform supports it, and nothing needs configuring. It's the slowest and uses the most disk, but it's never the reason a project fails to install.

If you're still on npm, try Bun on your own project. Install it, then run it in your project folder:

npm install -g bun
bun install

Bun reads your existing package.json and creates its own bun.lock. Compare the time with your usual npm install. On my project, that was the difference between 40 seconds and under 3.

A note on the numbers: these are medians of three runs on one machine with a fast datacenter connection. Your results will vary with your network, hardware and dependency tree, but the gaps between the tools should look similar.

MORE ARTICLES