Package managers are something most developers set up once and forget — until something breaks, or a teammate uses a different one and your node_modules becomes a mess.
In 2026, the three main contenders are still npm, Yarn, and pnpm. My short answer: pnpm for almost everything new. Here's why.
Quick Comparison
| Feature | npm | Yarn (v1/Berry) | pnpm |
|---|---|---|---|
| Speed | Baseline | ~2x faster | ~3x faster |
| Disk usage | High (copies) | High/PnP | Very low (hard links) |
| Monorepo | Workspaces (basic) | Workspaces (mature) | Workspaces (best) |
| Lockfile | package-lock.json | yarn.lock | pnpm-lock.yaml |
| Phantom deps | Yes (problem) | Yes/No (PnP) | No (strict) |
| Node built-in | Yes | No | No |
Speed: pnpm Dominates
pnpm uses a content-addressable store — packages are stored once on disk and hard-linked into projects.
# Installing a fresh React + TypeScript project
npm install: ~18s
yarn install: ~9s
pnpm install: ~5s
# Second install (cache warm)
npm install: ~9s
yarn install: ~4s
pnpm install: ~1.5s
For CI pipelines running dozens of builds per day, this adds up fast.
Phantom Dependencies: pnpm's Killer Feature
With npm and Yarn, your code can accidentally import packages not in your package.json — they're hoisted into node_modules as transitive dependencies.
// This might work with npm but correctly FAILS with pnpm:
import { something } from 'a-transitive-dep-you-never-declared'
pnpm uses a symlinked node_modules structure — you can only import what you've explicitly declared. This catches real bugs that npm/Yarn silently allow.
Monorepos: pnpm Wins Again
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
pnpm --filter @myapp/ui build
pnpm --filter @myapp/api add express
pnpm -r test # run all workspace tests in parallel
Turborepo, Nx, and most monorepo tools work great with pnpm.
When to Stick with npm
npm makes sense when:
- Writing a public npm package (familiar to all contributors)
- You need zero setup for a quick script
- Your team is non-JS-primary and just needs something that works
npm v9/10 is significantly better than older versions, but still the slowest of the three.
When to Use Yarn
- Yarn 1 (Classic): In maintenance mode. Don't start new projects with it.
-
Yarn Berry (v2+): Plug'n'Play eliminates
node_modulesentirely — but tooling compatibility is still patchy. Worth it only if you're fully committed to zero-install workflows.
Migration: npm/Yarn → pnpm
# Install pnpm
npm install -g pnpm # or: corepack enable pnpm
# In your project root
pnpm import # converts existing lockfile to pnpm-lock.yaml
rm -rf node_modules package-lock.json yarn.lock
pnpm install
Most projects migrate in under 30 minutes. The main fix: phantom dependency imports that pnpm correctly rejects.
My Pick in 2026
| Scenario | My Pick |
|---|---|
| New project (any type) | pnpm |
| Monorepo | pnpm |
| Public npm package | npm (contributor familiarity) |
| Existing Yarn 1 | Stay, migrate when ready |
Conclusion
In 2026, pnpm is the best default choice for the vast majority of JavaScript projects. Faster installs, lower disk usage, strict dependency resolution, and excellent monorepo support.
npm is fine for quick scripts and public packages. Yarn Berry has interesting ideas but adds friction. For everything else — start with pnpm.
I'm Jake, a senior frontend developer. More comparisons: Vitest vs Jest 2026
Top comments (0)