pnpm vs Bun vs npm: Package Manager Comparison 2026
Bun's package manager is 10-30x faster than npm on cold installs and 2-3x faster than pnpm. pnpm uses 70% less disk space than npm by storing packages once in a global store and hard-linking them. npm v11 (shipping with Node.js 24) is finally competitive — 65% faster large installs than v10. These aren't subtle differences. For large teams running CI hundreds of times a day, the choice of package manager has real cost and time implications.
TL;DR
pnpm for monorepos and teams where disk efficiency and correct dependency isolation matter — the production standard. Bun for maximum speed and new projects where Node.js compatibility edge cases don't apply. npm when you need maximum compatibility and are already on Node.js 24 with v11. For most teams upgrading from npm in 2026, pnpm is the safe, correct choice.
Key Takeaways
- npm v11 (Node.js 24): 65% faster than v10, improved workspace support, widely used baseline
- pnpm: 70% less disk space via content-addressable store, strict dependency isolation, excellent monorepo support
- Bun: 10-30x faster than npm cold installs, 2-3x faster than pnpm, but Node.js compat edge cases
- pnpm workspace: Better than npm/yarn workspaces for dependency hoisting control
- Bun install: Uses npm-compatible package-lock.json format in v1.3+, improving compatibility
- All three: Support package.json, lockfiles, workspaces, and standard npm registry
The Package Manager Landscape
# Install speed comparison (cold install, large project, 500+ packages):
npm install: ~60s
pnpm install: ~15s
bun install: ~5s
# Disk usage (global store):
npm: 500 MB per project (duplicated across projects)
pnpm: 500 MB once (shared across all projects via hard links)
bun: Similar to pnpm approach
The speed difference matters most in CI pipelines. If your CI runs 100 times per day, shaving 45 seconds off installs saves 1.25 hours per day — and costs real money in CI minutes.
npm
Comes with: Node.js Current version: v11 (Node.js 24), v10 (Node.js 22) Weekly downloads: Dominant (ships with Node.js)
npm is the default package manager. Every Node.js developer has it. Every CI system has it. The question isn't whether to use npm — it's whether the tradeoffs of pnpm or Bun justify switching.
npm v11 Improvements (Node.js 24)
# Upgrade to npm v11 manually:
npm install -g npm@latest
# Key improvements in v11:
# - 65% faster large installs
# - Better workspace dependency resolution
# - Updated lockfile format (v3)
# - Improved peerDependency handling
Basic Usage
# Install all dependencies
npm install
# Add a package
npm install express
npm install -D typescript @types/node # Dev dependency
# Remove a package
npm uninstall lodash
# Run scripts
npm run build
npm run test
# Audit
npm audit
npm audit fix
npm Workspaces
// package.json (monorepo root)
{
"name": "my-monorepo",
"workspaces": ["packages/*", "apps/*"],
"scripts": {
"build": "npm run build --workspaces --if-present",
"test": "npm test --workspaces --if-present"
}
}
# Install in a specific workspace
npm install --workspace=packages/ui lodash
# Run script in all workspaces
npm run build --workspaces
# Run script in specific workspace
npm run test --workspace=apps/web
npm Limitations
- Slowest cold installs (even v11 is slower than pnpm and Bun)
- Flat node_modules: "phantom dependencies" — packages available without being listed in package.json
- Disk space: each project gets its own full node_modules (no global sharing)
- Workspace support is less ergonomic than pnpm
pnpm
Package: pnpm
Weekly downloads: 8M
GitHub stars: 29K
Creator: Zoltan Kochan
pnpm (Performant npm) solves npm's two biggest problems: speed and disk space. Its content-addressable store means every version of every package exists exactly once on your disk.
Installation
# Recommended: install via Node.js corepack
corepack enable
corepack prepare pnpm@latest --activate
# Or directly:
npm install -g pnpm
The Store: 70% Less Disk Space
# npm: Each project copies packages
project-a/node_modules/lodash/ (4 MB)
project-b/node_modules/lodash/ (4 MB — duplicate!)
project-c/node_modules/lodash/ (4 MB — duplicate!)
# pnpm: Global store + hard links
~/.pnpm-store/v3/lodash@4.17.21/ (4 MB — stored once)
project-a/node_modules/lodash → hard link to store
project-b/node_modules/lodash → hard link to store
project-c/node_modules/lodash → hard link to store
The package takes 4 MB on disk regardless of how many projects use it.
Strict Dependency Isolation
pnpm's key safety feature: packages can only use what they declare as dependencies.
// package.json of "my-package"
{
"dependencies": {
"express": "^4.18.0"
// lodash NOT listed
}
}
// This code:
const _ = require('lodash'); // Works with npm (phantom dependency)
// Fails with pnpm (correctly!)
pnpm's strict mode eliminates phantom dependencies — a class of bugs where code works locally but fails in production or other environments.
Monorepo Support
pnpm's workspace support is the most mature of the three:
# pnpm-workspace.yaml
packages:
- 'packages/*'
- 'apps/*'
- '!**/test/**'
# Install in all workspaces
pnpm install
# Add to specific workspace
pnpm add --filter web react
# Add to root
pnpm add -w -D typescript
# Run command in all packages
pnpm -r run build
# Run in packages matching filter
pnpm --filter "@org/*" build
Hoisting Control
# .npmrc — pnpm configuration
hoist-pattern[]=*eslint*
hoist-pattern[]=*babel*
# Only hoist specific packages to root — prevents others from phantom-importing
pnpm Performance
# Install times (warm cache, large project):
npm: ~30s
pnpm: ~8s
bun: ~3s
# Install times (cold, no cache):
npm: ~60s
pnpm: ~15s
bun: ~5s
pnpm's content-addressable store means subsequent installs of the same package versions are instant — the files are already on disk.
pnpm Limitations
- Not as fast as Bun
- Some packages with incorrect peer dependency declarations may behave differently
- Extra configuration needed for packages that expect flat node_modules (rare but real)
.pnpmfile.cjshooks can get complex for large monorepos
Bun
Package: bun (install via bun.sh)
Weekly downloads: 3M (growing fast)
GitHub stars: 75K
Creator: Oven sh
Bun is a complete JavaScript runtime with a built-in package manager. bun install is not a separate tool — it's part of the Bun runtime, implemented in Zig for maximum performance.
Installation
# Install Bun runtime (includes package manager)
curl -fsSL https://bun.sh/install | bash
# or
brew install bun
Install Speed
# Cold install (no cache):
bun install # ~5s for large project
# Warm install (local cache):
bun install # <1s — almost instant
# Why so fast:
# - Written in Zig, not JavaScript
# - Parallel downloads with HTTP/2 multiplexing
# - Binary lockfile format (bun.lockb) — faster to parse than JSON
# - Aggressive caching
Basic Usage
# Install all dependencies
bun install
# Add a package
bun add express
bun add -D typescript @types/node
# Remove a package
bun remove lodash
# Run scripts
bun run build
bun run test
# Execute any npm script
bun build # Same as bun run build
Workspaces
// package.json
{
"name": "my-monorepo",
"workspaces": ["packages/*", "apps/*"]
}
# Install in all workspaces
bun install
# Add to specific workspace
bun add --cwd packages/ui lodash
# Run script in all workspaces
bun --filter "*" build
npm Compatibility in Bun v1.3+
Bun v1.3 improved compatibility significantly:
# Bun reads and writes package-lock.json (npm format)
# This means npm users can switch to Bun without changing lockfiles
# Or use Bun's native lockfile (faster):
bun install --lockfile-only # Creates bun.lockb
When Bun Install Might Fail
# Edge cases where Bun install behaves differently from npm/pnpm:
# - Some packages with complex lifecycle scripts (preinstall, postinstall)
# - Packages with native binaries in edge cases
# - Very new packages not yet tested with Bun
# Test before switching:
bun install # Check for errors
bun test # Run your test suite
Bun Limitations
- Not 100% Node.js compatible (runtime differences affect some packages)
- Binary lockfile (bun.lockb) is not human-readable
- Less battle-tested in enterprise environments
- Some CI environments don't have Bun available by default
- Node.js compatibility issues may be silent (install works, runtime fails)
Comparison Table
| Feature | npm v11 | pnpm | Bun |
|---|---|---|---|
| Cold install (large) | ~60s | ~15s | ~5s |
| Warm install | ~30s | ~8s | <1s |
| Disk efficiency | Low (duplicated) | High (hard links) | High (similar) |
| Phantom dependencies | Yes (problem) | No (strict) | Partial |
| Monorepo support | Good | Excellent | Good |
| Node.js compatibility | 100% | 100% | ~95% |
| Lockfile format | JSON (readable) | JSON (readable) | Binary (bun.lockb) |
| Weekly downloads | Dominant | 8M | 3M |
| Comes with Node.js | Yes | No | No (separate runtime) |
Migration Guide
npm → pnpm
# Install pnpm
corepack enable && corepack prepare pnpm@latest --activate
# Import npm lockfile → pnpm lockfile
pnpm import # Reads package-lock.json, creates pnpm-lock.yaml
# Delete npm lockfile
rm package-lock.json
# Install
pnpm install
# Commit:
git add pnpm-lock.yaml
git rm package-lock.json
Add to .npmrc to prevent npm from being used accidentally:
# .npmrc
engine-strict=true
// package.json
{
"engines": { "pnpm": ">=9" },
"packageManager": "pnpm@10.4.0" // Enforces specific version
}
npm → Bun
# Install Bun
curl -fsSL https://bun.sh/install | bash
# Generate Bun lockfile from existing package.json
bun install
# Commit:
git add bun.lockb
git rm package-lock.json # Optional: keep for npm users
Which to Use in 2026
Keep npm if:
- Your team is on Node.js 24 with npm v11 and aren't hitting performance pain
- CI environments don't have pnpm/Bun available without extra setup
- Maximum compatibility with all packages is required
- You don't have a monorepo
Switch to pnpm if:
- Disk space or install speed is a concern
- You have a monorepo (pnpm workspaces are the best)
- Strict dependency isolation (no phantom dependencies) is important
- You want a battle-tested upgrade from npm with minimal risk
Use Bun if:
- Starting a fresh project with no legacy considerations
- Maximum install speed is a priority (CI cost or developer experience)
- You're already using Bun as your runtime
- Your dependency tree doesn't use packages known to have Bun incompatibilities
Compare package manager adoption trends on PkgPulse.
See the live comparison
View pnpm vs. bun vs npm on PkgPulse →