pnpm (Performant npm) is a drop-in replacement for npm built on two strong ideas: a global store on disk that holds only one copy of each package, and strict resolution that prevents phantom dependencies.
Why pnpm saves so much space
When you run npm install react, npm copies the files into your-project/node_modules/react/. If you have ten projects using React, you have ten identical copies on disk.
pnpm works differently:
- It downloads React once into a global store (
~/.local/share/pnpm/storeon Linux/macOS,%LOCALAPPDATA%\pnpm\storeon Windows). - In each project,
node_modules/react/is a hardlink pointing to the store files. One physical file, ten projects accessing it.
Concretely: on a machine with ten React projects, npm uses ~400 MB per project. pnpm uses ~40 MB (the shared store) regardless of how many projects there are.
Installing pnpm
Via npm (once):
Via corepack (included in Node since v16):
Verify:
Common commands
Install all dependencies for an existing project:
Add a package:
Add a devDependency:
Run a script defined in package.json:
Shorthand (without run) for common scripts:
Run a one-off command without installing globally:
Update all dependencies:
Remove a package:
Strict resolution: no more phantom dependencies
pnpm creates a non-flattened node_modules/ structure. Each package can only see its own declared dependencies. Your code cannot access lodash unless you have explicitly added lodash to your package.json.
This may seem restrictive, but it is a safety net: your build is reproducible and does not depend on the transitive dependencies of your dependencies.
pnpm and monorepos
pnpm has the best monorepo support among the three package managers. A pnpm-workspace.yaml file at the root is all you need to declare multiple packages:
packages:
- "packages/*"
- "apps/*"Packages in the workspace can reference each other with workspace:* as the version:
{
"dependencies": {
"@my-project/shared": "workspace:*"
}
}