pnpm — Performant npm — was built to fix the two specific complaints heaviest npm users have: wasted disk space and phantom dependencies. It does both, faster, with the same package.json file. That makes pnpm the easiest 'I want to leave npm' migration in this quest.
Disk space. npm copies every package into every project's node_modules. Ten projects using React means React is on disk ten times. pnpm stores every package version once in a global content-addressable store at ~/.pnpm-store/, then creates hard links into each project's node_modules. Ten projects, one React on disk. Real-world savings are 50-70%.
Phantom dependencies. npm's flat node_modules lets your code accidentally import packages not declared in package.json. pnpm uses a strict nested structure — packages are only reachable if you've explicitly declared them. Your import statements become honest about what they depend on, and missing deps fail loudly instead of working by accident.
pnpm v10 (January 2025) added security by default — lifecycle scripts (postinstall, etc.) are blocked unless you opt-in per package. That single change eliminates a huge class of supply-chain attacks where a malicious package's postinstall script ran arbitrary code on every install. SHA256 hashing throughout. An experimental Global Virtual Store for even faster cold installs.
pnpm reads the same package.json as npm. The lockfile is pnpm-lock.yaml instead of package-lock.json. The CLI surface is mostly drop-in compatible. Migration is one pnpm import command.