Skip to main content
Ganesh Joshi
Back to Blogs

pnpm vs npm vs Bun: which package manager in 2026

February 15, 20265 min read
Tips
Terminal with package manager output

Every JavaScript project needs a package manager. npm ships with Node.js and is the default. pnpm offers better disk efficiency and speed. Bun bundles a package manager with its runtime. Each has trade-offs for install speed, disk usage, monorepo support, and ecosystem compatibility.

Quick comparison

Feature npm pnpm Bun
Install speed Slowest Fast Fastest
Disk usage High Low (hard links) Medium
Monorepo support Workspaces First-class Workspaces
Lockfile package-lock.json pnpm-lock.yaml bun.lockb (binary)
Strictness Loose Strict Loose
Runtime Node.js Node.js Bun

npm

npm is the default package manager for Node.js. Every Node installation includes it.

Strengths

  • Zero setup: Already installed with Node
  • Universal support: Every tutorial assumes npm
  • Mature: Stable, well-documented, predictable

Usage

# Install dependencies
npm install

# Add package
npm install lodash

# Add dev dependency
npm install -D typescript

# Run script
npm run build

# Update packages
npm update

Workspaces

npm 7+ supports workspaces for monorepos:

{
  "workspaces": ["packages/*", "apps/*"]
}
# Install all workspaces
npm install

# Run script in specific workspace
npm run build -w packages/ui

Limitations

  • Flat node_modules with hoisting can hide dependency issues
  • Slower than pnpm and Bun for large projects
  • Higher disk usage (no deduplication across projects)

pnpm

pnpm (performant npm) uses a content-addressable store and hard links.

How it works

Instead of copying packages to each project's node_modules, pnpm:

  1. Downloads packages to a global store (~/.pnpm-store)
  2. Creates hard links from projects to the store
  3. Each package version exists once on disk
~/.pnpm-store/
├── lodash@4.17.21/
├── react@18.2.0/
└── typescript@5.0.0/

project-a/node_modules/
└── .pnpm/
    └── lodash@4.17.21 → ~/.pnpm-store/lodash@4.17.21

project-b/node_modules/
└── .pnpm/
    └── lodash@4.17.21 → ~/.pnpm-store/lodash@4.17.21

Strengths

  • Disk efficiency: Packages stored once, linked everywhere
  • Strict dependencies: Only declared dependencies are accessible
  • Fast: Hard links are instant, no copying
  • Monorepo-first: Excellent workspace support

Installation

# Via npm
npm install -g pnpm

# Via Corepack (Node.js 16.9+)
corepack enable pnpm

# Via Homebrew
brew install pnpm

Usage

Commands mirror npm:

pnpm install
pnpm add lodash
pnpm add -D typescript
pnpm run build
pnpm update

Workspaces

Create pnpm-workspace.yaml:

packages:
  - 'packages/*'
  - 'apps/*'
# Run in specific package
pnpm --filter ui build

# Run in all packages
pnpm -r build

# Add dependency to specific package
pnpm --filter web add react

Strict mode

pnpm enforces declared dependencies. You can't import packages you didn't declare:

// If "lodash" is not in package.json, this fails
import _ from 'lodash';
// Error: Cannot find module 'lodash'

This catches phantom dependencies that would break in other environments.

Bun

Bun is a JavaScript runtime that includes a package manager, bundler, and test runner.

Strengths

  • Extremely fast: Native implementation, no Node.js overhead
  • Drop-in replacement: npm-compatible commands
  • Binary lockfile: Faster parsing than JSON/YAML
  • Integrated tooling: Runtime + bundler + test runner

Installation

# macOS/Linux
curl -fsSL https://bun.sh/install | bash

# Windows (via scoop)
scoop install bun

Usage

bun install
bun add lodash
bun add -d typescript
bun run build
bun update

Speed

Bun's package manager is written in Zig and optimized for speed:

Operation npm pnpm Bun
Clean install ~30s ~15s ~5s
Cached install ~10s ~3s ~1s
Add package ~5s ~2s ~0.5s

Times vary by project size and network.

Binary lockfile

Bun uses bun.lockb, a binary format:

# Generate lockfile
bun install

# View as text
bun bun.lockb

Binary lockfiles are faster to parse but not human-readable.

Limitations

  • Different runtime (some Node APIs differ)
  • Smaller ecosystem than Node.js
  • Native modules may need recompilation
  • Binary lockfile harder to review in PRs

Choosing a package manager

Use npm when

  • You want zero setup and maximum compatibility
  • Your CI/documentation assumes npm
  • You're working on a simple project
  • Team familiarity is paramount

Use pnpm when

  • You manage multiple projects sharing dependencies
  • Disk space matters (CI caches, local development)
  • You use monorepos (pnpm has excellent support)
  • You want strict dependency enforcement

Use Bun when

  • Install speed is critical
  • You're willing to use the Bun runtime
  • You want integrated tooling (runtime + bundler + tests)
  • You're starting a new project

Mixing package managers

Avoid mixing package managers in a project. Lockfiles are incompatible:

Manager Lockfile
npm package-lock.json
pnpm pnpm-lock.yaml
Bun bun.lockb

Enforce with packageManager field:

{
  "packageManager": "pnpm@8.15.0"
}

Corepack respects this and uses the specified manager.

Monorepo considerations

Feature npm pnpm Bun
Workspace linking
Filtering -w flag --filter --filter
Hoisting control Limited Full Limited
Turborepo integration ✅ (recommended)

pnpm is often recommended for monorepos due to its strict dependency resolution and excellent filtering.

CI caching

Cache strategies differ by manager:

# npm
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}

# pnpm
- uses: actions/cache@v4
  with:
    path: ~/.pnpm-store
    key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}

# Bun
- uses: actions/cache@v4
  with:
    path: ~/.bun/install/cache
    key: bun-${{ hashFiles('bun.lockb') }}

Migration path

npm to pnpm

# Delete node_modules and lockfile
rm -rf node_modules package-lock.json

# Install with pnpm
pnpm install

Most projects migrate seamlessly. Fix any phantom dependency errors by adding missing packages to package.json.

npm to Bun

# Delete node_modules and lockfile
rm -rf node_modules package-lock.json

# Install with Bun
bun install

Test thoroughly—Bun's runtime may behave differently for some Node APIs.

Summary

npm is the safe default with universal compatibility. pnpm offers better speed and disk efficiency with strict dependency management—ideal for monorepos. Bun provides the fastest installs and integrated tooling but requires adopting its runtime. Choose based on your project's needs: compatibility (npm), efficiency (pnpm), or speed (Bun). Commit one lockfile and enforce a single manager per project.

Frequently Asked Questions

pnpm is a fast, disk-efficient package manager that uses a content-addressable store and hard links. Each package version is stored once globally and linked into projects, saving disk space.

Yes, Bun includes a package manager alongside its JavaScript runtime and bundler. bun install is very fast due to its native implementation and binary lockfile format.

Consider pnpm if you have multiple projects sharing dependencies, use monorepos, or want faster installs and less disk usage. For simple projects, npm works fine.

You should use one package manager per project and commit its lockfile. Mixing managers causes inconsistent installs. Use packageManager field in package.json to enforce.

Bun is typically fastest for installs due to its native implementation. pnpm is faster than npm, especially for repeat installs. All three are fast enough for most workflows.

Related Posts