← All articles
LANGUAGES JavaScript Package Managers in 2026: npm, pnpm, Yarn... 2026-02-09 · 5 min read · package-managers · npm · pnpm

JavaScript Package Managers in 2026: npm, pnpm, Yarn, and Bun

Languages 2026-02-09 · 5 min read package-managers npm pnpm yarn bun javascript

JavaScript Package Managers in 2026: npm, pnpm, Yarn, and Bun

Four package managers, one registry, and a lot of opinions. npm is the default that ships with Node.js. pnpm saves disk space and enforces correctness. Yarn Berry reimagined how dependencies are resolved. Bun treats package management as a feature of the runtime itself. Each makes different trade-offs, and the right choice depends on your project.

Feature Comparison

Feature npm (v10+) pnpm (v9+) Yarn Berry (v4) Bun
Default with Node.js Yes No No No (ships with Bun)
Lockfile package-lock.json pnpm-lock.yaml yarn.lock bun.lock
node_modules structure Flat (hoisted) Symlinked (strict) Plug'n'Play (no node_modules) Flat (hoisted)
Content-addressable store No Yes No (zip cache) No
Workspace support Yes Yes Yes Yes
Dependency patching Via patch-package Built-in Built-in No
Corepack compatible Yes Yes Yes No

Performance Benchmarks

Install times on a mid-size project (~800 dependencies, CI environment):

Scenario npm pnpm Yarn Berry (PnP) Bun
Clean install (no cache) 38s 18s 14s 8s
Clean install (warm cache) 22s 8s 6s 4s
Adding one dependency 12s 4s 3s 2s
CI install (lockfile, cache) 18s 7s 5s 3s
Disk usage 420 MB 290 MB 45 MB (PnP) 415 MB

These numbers are representative, not absolute. The relative ordering is consistent: Bun is fastest, Yarn PnP and pnpm are in the middle, npm is slowest. The disk usage gap is dramatic -- pnpm's content-addressable store keeps one copy per package version across all projects, and Yarn PnP uses compressed zips instead of extracted files.

npm: The Default

npm ships with Node.js. As of v10, it's competent -- not exciting, but competent. Every tutorial, CI template, and deployment guide assumes npm. Zero setup cost, zero onboarding friction.

The problem: npm's flat hoisting means your code can import packages you didn't declare as dependencies. This "phantom dependency" issue causes builds to work locally but fail elsewhere. npm is also the slowest installer by a significant margin.

Use npm when your team has no reason to switch or when you need guaranteed compatibility with every tool. There's nothing wrong with npm -- it's just not the best at anything specific.

pnpm: Correctness and Efficiency

pnpm stores every package version once in a global content-addressable store (~/.local/share/pnpm/store) and hard-links files into each project's node_modules. Install [email protected] in five projects and pnpm stores it once. npm would keep five full copies.

# Install via Corepack (recommended)
corepack enable && corepack prepare pnpm@latest --activate

pnpm install          # Install all deps
pnpm add express      # Add a package

pnpm's node_modules is non-flat -- each package can only access its declared dependencies. If you import a transitive dependency you didn't declare, pnpm throws a resolution error. This strictness catches real bugs that npm silently hides. When migrating, expect to add a few missing declarations to dependencies. That's pnpm showing you problems that were always there.

# Relax strictness if needed temporarily (.npmrc)
node-linker=hoisted

pnpm has the strongest monorepo workspace support. The --filter flag supports git-based change detection, dependency graph traversal, and glob patterns:

# pnpm-workspace.yaml
packages:
  - "packages/*"
  - "apps/*"
pnpm -r run build                              # Build all packages
pnpm -r --filter "...[origin/main]" run build   # Only changed packages
pnpm add zod --filter @myapp/api                # Add to specific workspace

Yarn Berry: Plug'n'Play and Zero-Installs

Yarn Berry (v2+, currently v4) made a radical bet: eliminate node_modules entirely. Plug'n'Play (PnP) replaces it with a .pnp.cjs resolution map and compressed zip archives in .yarn/cache/.

corepack enable && corepack prepare yarn@stable --activate
yarn init -2
yarn install
# Result: no node_modules. Instead: .pnp.cjs + .yarn/cache/*.zip

Because the cache is small compressed zips, you can commit it to git. A fresh clone needs no install step -- just yarn to regenerate the PnP map. This eliminates CI install time entirely:

# .yarnrc.yml
nodeLinker: pnp
enableGlobalCache: false
enableImmutableInstalls: true  # CI mode

The trade-off: PnP breaks tools that traverse node_modules directly. React Native, some ESLint configs, and tools that shell out to node without the PnP loader have historically had issues. Ecosystem support has improved in 2026, but you'll still hit edge cases with native addons.

Yarn provides a node-modules linker fallback, but at that point you lose PnP's benefits and should consider pnpm instead.

Bun: Speed as a Feature

Bun's package manager is built into the runtime, written in Zig, and optimized for raw throughput. bun install is consistently 5-10x faster than npm and 2-3x faster than pnpm.

bun install           # Install deps
bun add express       # Add a package
bun add -d vitest     # Add dev dependency
bun remove lodash     # Remove a package

Bun 1.2+ generates a text-based bun.lock (replacing the earlier binary bun.lockb). It can read package-lock.json, yarn.lock, and pnpm-lock.yaml for painless migration.

The limitations: Bun uses flat hoisting like npm, so phantom dependencies are possible. Workspace support works but lacks pnpm's filtering sophistication. Some packages with complex native compilation steps may fail -- Bun uses a trustedDependencies allowlist to control which packages run lifecycle scripts.

Use Bun when speed is your priority and you're already on the Bun runtime. The install speed advantage is most impactful in CI pipelines.

Monorepo Comparison

Feature npm pnpm Yarn Berry Bun
Workspace protocol * workspace:* workspace:* workspace:*
Selective execution --workspace --filter yarn workspace --filter
Parallel execution No Yes (-r) Yes (topological) Partial
Change-based filtering No Yes (git-based) Yes (plugin) No
Hoisting control Limited Granular Granular Limited

For serious monorepo usage, pnpm and Yarn Berry are clearly ahead.

Migration Guides

npm to pnpm

corepack enable && corepack prepare pnpm@latest --activate
rm -rf node_modules package-lock.json
pnpm import          # Import resolutions from old lockfile
pnpm install         # Install; fix any missing dependency declarations

npm/pnpm to Yarn Berry

corepack enable
yarn set version stable
rm -rf node_modules package-lock.json pnpm-lock.yaml
yarn install
# For node_modules fallback instead of PnP:
# echo 'nodeLinker: node-modules' >> .yarnrc.yml && yarn install

Any manager to Bun

bun install          # Reads existing lockfiles automatically
# Replace 'npx' with 'bunx' in scripts

Migration Checklist

Configuration Cheatsheet

pnpm (.npmrc)

strict-peer-dependencies=true
auto-install-peers=true
public-hoist-pattern[]=@types/*
frozen-lockfile=true

Yarn Berry (.yarnrc.yml)

nodeLinker: pnp
enableImmutableInstalls: true
plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
    spec: "@yarnpkg/plugin-typescript"

Bun (bunfig.toml)

[install]
frozenLockfile = true
trustedDependencies = ["esbuild", "sharp"]

Recommendations

Solo project or small team: Use pnpm. Correctness guarantees catch real bugs, speed is good, and ecosystem support is broad.

Large monorepo: Use pnpm or Yarn Berry. pnpm's --filter is excellent. Yarn PnP's zero-installs shine if your toolchain supports them. Evaluate both against your specific tools.

Bun runtime project: Use bun install. If Bun is your runtime, its package manager is the path of least resistance.

CI-sensitive project: Use Bun for speed or Yarn Berry zero-installs to skip the install step entirely.

Maximum compatibility: Use npm. Lowest risk, works everywhere, just slower.

Starting fresh with no constraints: Use pnpm. Best balance of speed, correctness, and ecosystem support. It's strict where it should be and flexible where it needs to be. Most teams that switch to pnpm don't switch back.