pnpm

pnpm is a JavaScript package manager that installs dependencies faster and with far less disk space than npm or classic Yarn, while being stricter about what code can import. Instead of copying every package into every project, pnpm keeps one copy of each package version in a global content-addressable store and hard-links files into projects. Instead of a flat node_modules where any package can reach any other, it builds a symlinked layout in which each package sees only the dependencies it declares.

That strictness catches real bugs — code importing packages it never listed — and pnpm's workspace features make it one of the most popular choices for monorepos. It is a drop-in replacement for most npm workflows: the same package.json, the same registry, a different lockfile (pnpm-lock.yaml).

TL;DR

Quick Example

A monorepo workspace with shared versions and supply-chain controls:

An app depending on a local package and a catalog version:

Day-to-day commands:

Core Concepts

The Content-Addressable Store

Every file of every package version is stored once in a global store, addressed by its content hash. Installing a package into a project creates hard links (or copy-on-write clones) to those files, so ten projects using the same React version share one copy on disk. Updating one version of a large package only stores the files that changed.

Strict, Symlinked node_modules

A phantom dependency is a package your code imports without declaring it — it works only because something else happened to install it. It breaks when that other dependency changes. pnpm surfaces these immediately.

Workspaces

pnpm-workspace.yaml lists the packages in a monorepo. The workspace: protocol links local packages instead of downloading them, and is replaced with real version ranges on publish. Filters select packages by name, directory, dependency relationships (... for dependents or dependencies), or changes since a git ref, which makes CI run only what a change affects. See Monorepos.

Catalogs and Overrides

Catalogs declare dependency versions once in the workspace file; packages refer to them with catalog:. Upgrading React across thirty packages becomes a one-line change. Overrides force a specific version of a transitive dependency, for example to patch a vulnerable package deep in the tree.

Security Controls

pnpm 10 changed the default for lifecycle scripts: dependencies' preinstall and postinstall scripts do not run unless the package is allowed (onlyBuiltDependencies, or interactively with pnpm approve-builds). Since many supply-chain attacks execute through install scripts, this closes a major hole. minimumReleaseAge delays adopting newly published versions, giving the ecosystem time to detect compromised releases. See Software Supply Chain Security.

pnpm Compared With Other Package Managers

See Package Managers and Bun.

Using pnpm in CI

Pin the pnpm version with the packageManager field in the root package.json so every developer and CI job uses the same version.

Best Practices

Commit the Lockfile and Freeze It in CI

pnpm-lock.yaml records exact versions and integrity hashes. CI should fail if it is out of date rather than silently resolving new versions.

Fix Phantom Dependencies, Do Not Hide Them

When a strict import fails, add the missing dependency to the package that imports it. Hoisting everything back to the top level gives up pnpm's main safety benefit.

Approve Build Scripts Deliberately

Allow install scripts only for packages that genuinely need them, such as native modules, and review the list when it changes.

Use Catalogs for Shared Versions

Keep frameworks, TypeScript, and test tools on one version across the monorepo with catalogs instead of dozens of independent ranges.

Common Mistakes

Mixing Package Managers

Hoisting Everything for Compatibility

Relying on Implicit Workspace Resolution

FAQ

Why is pnpm faster than npm?

It reuses files from a global store via hard links instead of copying them, resolves and fetches in parallel, and skips work for packages already in the store. Projects that share dependencies install especially quickly.

Is pnpm compatible with npm packages?

Yes. It uses the same registry and package.json format. Occasionally, packages that rely on undeclared dependencies break under pnpm's strict layout; the fix is usually declaring the dependency or a targeted configuration.

What is a phantom dependency?

A package your code imports without listing it in package.json, which only works because another dependency installed it. pnpm's strict layout makes such imports fail, exposing the missing declaration.

Does pnpm run postinstall scripts?

Since pnpm 10, dependency lifecycle scripts do not run by default. You allow specific packages through onlyBuiltDependencies or by approving them with pnpm approve-builds.

Should I use pnpm or Bun?

pnpm is a mature, highly compatible package manager with strong monorepo features. Bun is a whole runtime and toolkit with a very fast installer. Many teams use pnpm with Node.js for compatibility and use Bun where its runtime fits.

Related Topics

References