Skip to main content

pnpm vs Bun vs npm: Package Managers 2026

·PkgPulse Team
0

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.cjs hooks 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

Featurenpm v11pnpmBun
Cold install (large)~60s~15s~5s
Warm install~30s~8s<1s
Disk efficiencyLow (duplicated)High (hard links)High (similar)
Phantom dependenciesYes (problem)No (strict)Partial
Monorepo supportGoodExcellentGood
Node.js compatibility100%100%~95%
Lockfile formatJSON (readable)JSON (readable)Binary (bun.lockb)
Weekly downloadsDominant8M3M
Comes with Node.jsYesNoNo (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

CI Pipeline Configuration

Choosing the right package manager also means configuring CI correctly to take advantage of caching. Here is how each package manager looks in a GitHub Actions workflow:

# pnpm in GitHub Actions
- uses: pnpm/action-setup@v3
  with:
    version: 10
- name: Get pnpm store directory
  id: pnpm-cache
  run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
  with:
    path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
    key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
- run: pnpm install --frozen-lockfile
# Bun in GitHub Actions
- uses: oven-sh/setup-bun@v1
  with:
    bun-version: latest
- name: Cache Bun dependencies
  uses: actions/cache@v3
  with:
    path: ~/.bun/install/cache
    key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
- run: bun install --frozen-lockfile

pnpm's frozen lockfile mode (--frozen-lockfile) ensures CI installs exactly what is in version control and fails loudly if the lockfile is out of date. Bun has the same flag. npm uses --ci for the same guarantee. All three support deterministic installs in CI.

The cache key strategy matters significantly for CI cost. pnpm's content-addressed store means cache hits are more granular — if only one package changes, the rest of the store is still cached. This makes pnpm's CI caching strategy particularly efficient for large projects.

Package Manager and Monorepo Tooling

Package manager choice and monorepo tooling are coupled decisions. The major build orchestration tools each have official recommendations:

Turborepo supports all three but officially recommends pnpm for its workspace features and dependency graph accuracy. Turborepo's remote caching integrates well with pnpm's content-addressed store. For teams running Turborepo, pnpm is the path of least resistance.

Nx similarly supports all three. The Nx team has invested heavily in pnpm integration. Their Nx Cloud remote caching works with both pnpm and npm. Bun support in Nx is available but community-maintained rather than first-party.

Moon (from the moonrepo team) lists pnpm as its primary supported package manager, with Bun support added in 2025. Teams using Moon for monorepo task orchestration should default to pnpm.

For teams evaluating the full monorepo toolchain, the best monorepo tools 2026 comparison covers Turborepo, Nx, and Moon in depth alongside their package manager recommendations.

Lockfile Strategy for Teams

Lockfiles prevent dependency drift between developer machines and CI. Each package manager has a different lockfile format with different characteristics:

  • package-lock.json (npm): JSON format, human-readable, large file size, well-understood diff behavior
  • pnpm-lock.yaml (pnpm): YAML format, human-readable, compact, includes integrity hashes
  • bun.lockb (Bun): Binary format, not human-readable, smallest file size, fast to parse

For teams using code review workflows, the human-readable formats of npm and pnpm lockfiles are easier to review in PRs. The binary lockfile format of Bun means lockfile changes in PRs show only as binary diffs — you can see it changed but not what changed. Teams with strict dependency review requirements often prefer pnpm for this reason.

Performance in the JavaScript Toolchain Context

Package install speed is one component of total developer feedback loop time. For teams already using Oxlint vs ESLint for fast linting, and a fast bundler like Vite or Rspack, shaving 10 seconds from package installs is less impactful than shaving 10 seconds from the lint step. Optimize the whole pipeline rather than any single tool in isolation.

That said, cold install speed matters most at two points: initial project setup (affects onboarding time for new developers) and CI cache misses (affects incident response when you need to merge quickly). Bun's cold install advantage is most valuable precisely in these high-pressure scenarios.

Teams building Node.js applications should also consider the testing layer when evaluating package managers. Bun test vs Vitest vs Jest explores how Bun's built-in test runner compares to the JavaScript testing ecosystem — if you are adopting Bun as your runtime, its test runner may replace both your test framework and package manager simultaneously. This integrated approach is compelling for new projects but represents a large surface area change for existing codebases.


Ecosystem & Community

The package manager ecosystem in 2026 has stabilized around these three tools, with Yarn (classic and berry) having lost significant mindshare to pnpm and Bun. pnpm's community is the most technically engaged — the GitHub issues for pnpm are consistently detailed, the maintainers are responsive, and the community around monorepo tooling (Turborepo, Nx, moon) has aligned closely with pnpm as the package manager of choice.

Bun's community is large and enthusiastic, driven by its positioning as a complete JavaScript runtime replacement. The Bun Discord has tens of thousands of members, and the project generates significant developer excitement. The pace of development is fast — Bun ships updates weekly and the changelog is consistently impressive. The trade-off is that this speed means occasional regressions, and enterprise teams often wait several versions before adopting new Bun releases.

npm's community is simply the Node.js community — universal but less specialized. The npm registry remains the central package distribution infrastructure for all three package managers, and npm's governance through GitHub (Microsoft acquisition) provides the institutional stability that ensures the registry infrastructure continues to be maintained.


Real-World Adoption

pnpm has become the dominant choice for JavaScript monorepos. The major open-source monorepo tooling projects (Turborepo, Nx, Lerna) all list pnpm as the recommended package manager. Companies that manage large monorepos — Microsoft (TypeScript), Google (Angular), and numerous scale-stage startups — have standardized on pnpm for its disk efficiency and dependency isolation guarantees.

Bun has attracted adoption among solo developers and small teams building new projects who want maximum speed and are willing to accept some compatibility risk. The developer tooling community has been particularly receptive — many CLI tools, developer utilities, and small packages have migrated their development environment to Bun, even when their distribution target is still Node.js.

npm remains dominant for legacy projects, simple applications, and anywhere that Node.js is the runtime and there's no specific reason to switch. npm v11's performance improvements have reduced the urgency for teams that were previously considering migration primarily for speed reasons.


Developer Experience Deep Dive

pnpm's developer experience has the highest learning curve of the three, but the rewards are real. The phantom dependency protection catches bugs before they reach production — particularly valuable in large monorepos where transitive dependencies can silently become implicit dependencies. The hoisting configuration in .npmrc gives granular control over which packages are accessible from where, enabling strict module boundaries.

Bun's developer experience is the fastest feedback loop. bun install on a warm cache completes in under a second, bun add installs new packages almost instantly, and bun run starts scripts faster than npm. The integration between Bun's package manager and Bun's runtime means running bun dev in a Bun project starts both the dependency installation check and the dev server in a single command. For developers who work on multiple projects throughout the day, Bun's speed compounds into meaningful time savings.

npm's developer experience is the most familiar and lowest friction. Every tutorial, every Stack Overflow answer, and every CI example in the world uses npm syntax. For teams that don't have a specific pain point with npm — no monorepo complexity, no disk space pressure, acceptable install times — the migration overhead to pnpm or Bun may not be justified. The onboarding benefit is also real: new developers on npm-based projects can be productive immediately without learning pnpm-specific flags or Bun-specific behaviors. This matters in teams with high developer turnover or frequent contractor engagement.


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

The decision comes down to two primary axes: team size and project structure. Solo developers and small teams on new projects benefit most from Bun's speed with minimal compatibility risk — the narrower dependency tree reduces the chance of hitting edge cases. Large teams with existing monorepos benefit most from pnpm's strict isolation and mature workspace tooling — the investment in learning pnpm's configuration pays dividends across every developer and every CI run.

Node.js version is also a factor. Teams running Node.js 24 with npm v11 who aren't hitting specific pain points have less incentive to switch than teams still on npm v9 or v10. The performance gap between npm v11 and pnpm has narrowed enough that for teams not managing monorepos, the migration may not be worth the friction.


Final Verdict 2026

For teams with a greenfield project or the bandwidth to migrate: pnpm is the recommendation for anything with a monorepo, and Bun is compelling for new single-package projects where raw speed matters. For teams running npm v11 without specific pain points, the migration ROI may not justify the switch.

The package manager choice has become less consequential than it was three years ago — all three tools produce correct installs from the npm registry, support workspaces, and integrate with modern CI systems. The differences are real but incremental. pnpm's disk efficiency is genuinely valuable at scale; Bun's speed is genuinely impressive; npm's compatibility is genuinely useful. Choose based on your specific constraints rather than trend following.

Compare package manager adoption trends on PkgPulse.

Compare pnpm, Bun, and npm package health on PkgPulse.

Related:

Best monorepo tools in 2026

Bun test vs Vitest vs Jest

Vite vs Rspack vs webpack bundler comparison

When to Switch

Migration between package managers is lower risk than it looks. The npm registry is the common substrate — switching is mostly a config and lockfile change, not a dependency change.

Switch to pnpm if you are running a monorepo with shared dependencies across packages, or if your CI cache costs are significant. The content-addressed store eliminates redundant downloads across packages and across CI runs when the cache is warmed. The --frozen-lockfile flag and strict module resolution also catch dependency issues earlier than npm's more permissive defaults.

Switch to Bun if install speed is a genuine pain point and your team is not on Windows. Bun's cold install speed is real — the difference is noticeable on large dependency trees. The catch is ecosystem maturity: some npm lifecycle scripts and native modules behave differently under Bun's runtime, and the Windows support gaps matter if any team member is on Windows.

Stay on npm if you are optimizing for predictability and zero surprise. npm is the reference implementation, and npm 10's performance improvements have narrowed the gap enough that switching for speed alone is hard to justify. For small-to-medium projects with a single package.json, npm is fine.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.