Skip to main content

Side by side

npmvspnpm

What is the difference between npm and pnpm?

Updated 3 min read8 differences

In short

npm copies every package into each project's flat node_modules; pnpm keeps one copy in a shared store, links it in and blocks undeclared imports.

npm

Node Package Manager

npm is Node.js's default package manager and the world's largest software registry; it downloads a project's dependencies and tracks their versions.

Read the page on npm

pnpm

Performant npm

pnpm is a fast, disk-efficient JavaScript package manager that keeps one copy of each package version in a shared store and links it into projects.

Read the page on pnpm

npm and pnpm compared

Aspectnpmpnpm
Disk usageA full copy of every package in each projectOne copy per version in a shared store, hard-linked into projects
Folder layoutFlat: dependencies are hoisted to the top levelStrict: only direct dependencies at the top, linked into .pnpm
Undeclared importsOften work by accident (phantom dependencies)Fail right away
Lockfilepackage-lock.jsonpnpm-lock.yaml
Repeat installsUnpacks and copies every package again from its cacheLinks files already in the store; usually faster
Install scriptsDependencies' scripts run by defaultBlocked since version 10 until you approve them
MonoreposWorkspaces with --workspace flagspnpm-workspace.yaml with --filter
SetupShips with Node.jsInstalled separately, often with Corepack or npm install -g pnpm

The difference, explained

npm and pnpm are both JavaScript package managers that read the same package.json and install from the same npm registry. npm is the default and ships with every installation of Node.js. pnpm, short for performant npm, is a separate tool built to save disk space, speed up installs and keep dependencies strict; anything published to npm installs with it.

The difference is where the files go. npm copies every dependency into each project's node_modules and hoists them into one flat folder, so ten projects that use React hold ten copies of it, and your code can import a package it never declared just because a dependency pulled it in: a phantom dependency. pnpm saves each file once in a content-addressable store and hard-links it into projects, and its node_modules holds only your direct dependencies, as symbolic links into node_modules/.pnpm, so undeclared imports fail right away.

The commands are close: pnpm add react for npm install react, pnpm dlx for npx, and pnpm import turns an existing package-lock.json into pnpm-lock.yaml. pnpm is popular for monorepos, with a pnpm-workspace.yaml file and a --filter flag that runs commands in only some packages. It is also stricter about security: since version 10 it doesn't run dependencies' install scripts unless you approve them, while npm runs them by default unless you pass --ignore-scripts.

A common misconception is that pnpm is a fork of npm or a separate registry; it is neither, only a different way of laying packages out on disk. Its strictness sometimes breaks older packages that relied on hoisting, which is a hidden bug in those packages rather than in pnpm, and pnpm has hoisting settings that loosen the layout for such cases. As with any package manager, a project should use one and commit only its lockfile.

Which one should you use?

Choose npm when…

  • You want the default tool that comes with Node.js, with nothing else to install.
  • Your host, CI images or tutorials assume npm and package-lock.json.
  • Older tools in the project expect a flat node_modules folder.

Choose pnpm when…

  • Disk space or install time matters, across many projects or in CI.
  • You want undeclared imports to fail instead of working by accident.
  • You run a monorepo and want --filter and workspace links.
  • You want dependencies' install scripts blocked until you approve them.

Installing Express, then importing a package that was never declared

npmbash
# npm: dependencies are hoisted into one flat folder
npm install express
ls node_modules
# accepts  body-parser  ...  debug  ...  express  ...

# debug is not in package.json, but this works
node -e "require('debug')"
pnpmbash
# pnpm: only declared dependencies sit at the top
pnpm add express
ls node_modules
# express   (a link into node_modules/.pnpm)

# debug was never declared, so this fails
node -e "require('debug')"
# Error: Cannot find module 'debug'

Readers ask

Is pnpm faster than npm?

On repeat installs, usually yes: files already in the store are linked instead of unpacked and copied again. The gap depends on the project and on whether the store is already filled, so first installs on a clean machine are closer.

Does pnpm work with every npm package?

Almost all of them, since it installs from the same registry. A few older packages import dependencies they never declared and break under pnpm's strict layout; its hoisting settings make the layout looser for those.

How do I switch a project from npm to pnpm?

Run pnpm import to create pnpm-lock.yaml from package-lock.json, delete the old lockfile and node_modules, then run pnpm install. Record pnpm in the packageManager field so everyone uses the same tool.

More

Settings