---
title: "Yarn vs pnpm"
slug: "yarn-vs-pnpm"
category: "comparisons"
tags: ["comparisons", "yarn", "pnpm", "package-manager", "monorepo", "node", "tooling"]
status: "stable"
last_updated: 2026-05-14
summary: "Use pnpm by default for disk efficiency and strict dependency isolation; use Yarn Berry only when Plug'n'Play or its workspaces features are a real requirement."
related: ["[[comparisons/vite-vs-webpack]]", "[[comparisons/swc-vs-babel]]", "[[comparisons/turborepo-vs-nx]]", "[[howto/migrate-from-npm-to-pnpm]]", "[[coding/general-principles]]", "[[tooling/github]]", "[[ops/github-pages]]"]
---

## Overview

Use pnpm for new projects. It installs faster than Yarn on most machines, uses a content-addressable store that saves gigabytes across projects, and enforces strict dependency isolation so phantom dependencies cause build errors rather than silent runtime bugs. Use Yarn Berry (v4) only when Plug'n'Play mode, Yarn's constraint engine, or its specific protocol handlers (`portal:`, `patch:`) are genuine requirements on the project. See [[howto/migrate-from-npm-to-pnpm]] for the migration steps.

## When pnpm wins

pnpm is the default for most new projects and monorepos.

- Disk efficiency: pnpm uses a global content-addressable store. Every version of every package is stored once on disk and hard-linked into each project's `node_modules`. A machine running 20 Node projects typically saves 5 to 15 GB compared to npm or Yarn.
- Speed: install times are 30 to 50 percent faster than `npm install` and comparable to Yarn on cache hits. The store means cold installs on a new machine reuse packages from other projects.
- Strict isolation: pnpm does not hoist all packages to the top-level `node_modules`. A package can only import what it declares in its own `package.json`. Phantom dependency bugs surface during install, not in production.
- Monorepo workspaces: `pnpm-workspace.yaml` is simple and well-understood. `pnpm -r run build` runs a command in all workspace packages in topological order.
- Compatibility: pnpm is compatible with `package.json` and the npm registry. CI environments support it via `actions/setup-node` with `cache: pnpm`.

```yaml
# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"
```

## When Yarn wins

Yarn Berry (v4) wins in specific cases.

- Plug'n'Play (PnP) mode: Yarn PnP eliminates `node_modules` entirely, replacing it with a `.pnp.cjs` loader. Build times drop and the install is reproducible without `node_modules` in the repo. The constraint is that every package in the dependency graph must be PnP-compatible. Some native modules and older packages are not.
- `patch:` protocol: Yarn's `patch:` resolution lets you patch an upstream package inline with a diff checked into the repo, without forking the package. pnpm has `pnpm patch` which is similar but Yarn's is more mature.
- Constraint engine: Yarn's constraint system enforces workspace-level rules (consistent dependency versions across packages) using a Prolog-like DSL. pnpm has `syncpack` as an external alternative.
- Existing Yarn v1 codebase committed to Berry upgrade: incremental migration within the Yarn ecosystem.

## Trade-offs at a glance

| Dimension                  | pnpm                                    | Yarn Berry (v4)                              |
| -------------------------- | --------------------------------------- | -------------------------------------------- |
| Disk usage                 | Low (global content store)              | Very low with PnP; standard with node-modules linker |
| Install speed              | Fast                                    | Fast; fastest with PnP and zero-installs     |
| Phantom dependency safety  | Strict isolation by default             | PnP catches them; node-modules linker does not |
| Monorepo workspaces        | `pnpm-workspace.yaml`                   | `workspaces` in `package.json`               |
| PnP support                | No                                      | First-class                                  |
| Patch protocol             | `pnpm patch` (file-based)               | `patch:` in resolutions (diff-based)         |
| Constraint engine          | External tools (syncpack)               | Built-in Prolog DSL                          |
| CI cache setup             | Standard via `actions/setup-node`       | Requires `.yarn/cache` config                |
| Compatibility              | High; works with most packages          | PnP has friction with non-compliant packages |
| Community traction         | Growing; default in many starters       | Stable; Meta, large monorepos                |

## Migration cost

npm or Yarn v1 to pnpm is typically low-effort.

- Remove `node_modules` and `yarn.lock` or `package-lock.json`.
- Run `pnpm import` to generate `pnpm-lock.yaml` from the existing lock file.
- Replace `npm run` or `yarn` calls in CI and scripts with `pnpm`.
- Fix any phantom dependency issues that surface. These are real bugs; fixing them is a feature.
- Effort: half a day for a single-package project; one to two days for a monorepo with many packages.

See [[howto/migrate-from-npm-to-pnpm]] for the step-by-step.

## Recommendation

- New project: pnpm.
- New monorepo: pnpm with `pnpm-workspace.yaml`. Pair with Turborepo for caching; see [[comparisons/turborepo-vs-nx]].
- Existing Yarn v1 project: migrate to pnpm. Yarn v1 is in maintenance mode.
- Existing Yarn Berry project with PnP working: stay; the migration cost is not justified.
- CI: enable pnpm store caching from day one to make remote installs fast.

## Related

- [[comparisons/vite-vs-webpack]]
- [[comparisons/swc-vs-babel]]
- [[comparisons/turborepo-vs-nx]]
- [[howto/migrate-from-npm-to-pnpm]]
- [[coding/general-principles]]
- [[tooling/github]]
