npm vs yarn vs pnpm: The Honest Comparison
All three install packages from the npm registry. All three use package.json. The differences are in speed, disk usage, and how they handle the node_modules folder.
Quick Comparison
| Feature | npm | Yarn (v4) | pnpm |
|---|---|---|---|
| Speed (cold install) | Slowest | Fast | Fastest |
| Disk usage | Duplicates packages | Plug'n'Play (no node_modules) | Content-addressable store (shared) |
| Monorepo | Workspaces | Workspaces (better) | Workspaces (best) |
| Strictness | Hoists everything | Strict by default (PnP) | Strict (no phantom deps) |
| Comes with Node.js | Yes | Via Corepack | Separate install |
| Lock file | package-lock.json | yarn.lock | pnpm-lock.yaml |
Installation Commands
# Install all dependencies
npm install yarn install pnpm install
# Add a package
npm install express yarn add express pnpm add express
# Add dev dependency
npm install -D jest yarn add -D jest pnpm add -D jest
# Remove a package
npm uninstall lodash yarn remove lodash pnpm remove lodash
# Run a script
npm run dev yarn dev pnpm dev
# Execute a binary
npx create-next-app yarn dlx create-next-app pnpm dlx create-next-app
# Update packages
npm update yarn up pnpm updateWhy pnpm Is Fast
pnpm uses a content-addressable store. When you install lodash@4.17.21 in project A, it's downloaded once to a global store. Project B that needs the same version gets a hard link — no duplication. This means:
- Faster installs: Packages already in the store aren't downloaded again
- Less disk space: 100 projects using React don't mean 100 copies
- Strict node_modules: Packages can only access their declared dependencies (no phantom dependencies)
Why Yarn PnP (Plug'n'Play)
Yarn can eliminate node_modules entirely. Instead, it creates a .pnp.cjs file that maps imports to zip archives in .yarn/cache/. Benefits:
- Zero installs: Commit the cache to git, CI doesn't need to install at all
- Instant installs: No file system operations (no 50,000 files in node_modules)
- Caveat: Some tools don't support PnP and need compatibility plugins
Phantom Dependencies
npm and yarn classic "hoist" dependencies, meaning your code can accidentally import packages you didn't declare in package.json. This works on your machine but breaks when that transitive dependency is removed.
// You never installed 'glob' — it's a dep of another package
import glob from 'glob'; // Works with npm (hoisted)
// Fails with pnpm (strict mode) — forces you to declare it properlypnpm prevents this by default. Your code can only import what's in your package.json.
Which One to Pick
- npm: Default choice, works everywhere, good enough for most projects
- pnpm: Best for monorepos, disk-constrained CI, teams that want strict deps
- yarn: If you want PnP/zero-installs or your team already uses it
Honestly? Pick any one and stick with it. The speed differences are seconds, not minutes. Consistency within a team matters more than benchmarks.
Manage your packages: JSON Formatter — format and validate your package.json files.