LEARN · DEBUGGING GUIDE

Debugging pnpm Peer Dependency Conflicts

When pnpm's strict dependency resolution meets peer dependency mismatches, you get cryptic errors. Here's exactly how to diagnose and fix them.

IntermediateBuild tools7 min read

What this usually means

pnpm uses a strict dependency resolution algorithm that creates a flat node_modules structure but enforces peer dependency constraints at install time. When a package declares a peer dependency (e.g., 'react': '^17.0.0') and the resolved version in your project is incompatible (e.g., React 18), pnpm refuses to install and reports the conflict. Unlike npm or Yarn, pnpm does not auto-install peer dependencies; it expects you to explicitly add them. The conflict arises when multiple packages demand overlapping but incompatible peer ranges, or when you forget to add a peer dependency entirely.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run 'pnpm install --no-frozen-lockfile' and capture the full error output — it lists the exact packages and missing peers.
  • 2Check your root package.json's 'dependencies' or 'devDependencies' for the reported peer package version.
  • 3Run 'pnpm ls --depth Infinity --json | jq .' to see the dependency tree and spot multiple versions of the peer.
  • 4Search your project for the peer package name in pnpm-lock.yaml to see which packages require it and what version range they specify.
  • 5Use 'pnpm why <package-name>' to trace which top-level dependency brought in a conflicting version.
  • 6If the error mentions a specific version, try 'pnpm add <peer-package>@<exact-version>' to satisfy it explicitly.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchpackage.json — root dependencies and resolutions field.
  • searchpnpm-lock.yaml — under 'packages', look for the peer package entries and their 'resolution' versions.
  • search.npmrc — check for 'strict-peer-dependencies=false' or 'auto-install-peers=true' settings.
  • searchnode_modules/.pnpm — the virtual store; inspect with 'ls -la node_modules/.pnpm/<peer-package>'.
  • searchThe output of 'pnpm list --recursive --depth Infinity' — shows the full tree.
  • searchAny workspace package.json files if using pnpm workspaces (monorepo).
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningMissing peer dependency: A package requires a peer that is not listed in your root package.json.
  • warningVersion mismatch: The peer dependency's version range does not include the installed version (e.g., requires ^16 but you have React 18).
  • warningTransitive peer conflict: Two dependencies require different versions of the same peer, and pnpm cannot hoist both.
  • warningOverly strict peer range: A library specifies an exact version or a narrow range that your project doesn't meet.
  • warningForgetting to add peer dependencies when upgrading a major version (e.g., React Router requires React 16.8+ but you have React 16.0).
  • warningInconsistent peer specs across workspace packages: Two packages in a monorepo require different versions of the same peer.
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildAdd the missing peer dependency explicitly to your root package.json with a version that satisfies all constraints.
  • buildUse pnpm's 'overrides' field in package.json to force a specific version of the peer package across all dependencies.
  • buildSet 'strict-peer-dependencies=false' in .npmrc as a temporary workaround (not recommended for production).
  • buildSet 'auto-install-peers=true' in .npmrc to let pnpm auto-install missing peer dependencies (use with caution).
  • buildUpdate the conflicting dependency to a newer version that supports the peer version you have.
  • buildUse 'pnpm add -D <peer-package>@<version>' to add the peer as a devDependency if it's only needed for development.
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedRun 'pnpm install' with --frozen-lockfile and confirm zero errors.
  • verifiedRun 'pnpm ls --depth 0 | grep <peer-package>' to verify only one version is installed.
  • verifiedCheck pnpm-lock.yaml for the peer package — it should appear only once with the correct version.
  • verifiedBuild the project (e.g., 'npm run build') and verify no module resolution errors.
  • verifiedRun the test suite to ensure runtime behavior is correct.
  • verifiedIf using TypeScript, run 'tsc --noEmit' to check type compatibility.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningSetting 'strict-peer-dependencies=false' without understanding the consequences — it can mask real conflicts and cause runtime failures.
  • warningManually editing pnpm-lock.yaml — it will be overwritten on the next install and can introduce inconsistencies.
  • warningAdding a peer dependency as a regular dependency when it's only needed for development (use devDependencies).
  • warningIgnoring peer dependency warnings — even if install succeeds, runtime errors can occur.
  • warningUpgrading a peer dependency without upgrading all packages that depend on it.
  • warningUsing 'pnpm add <package> --save-peer' incorrectly — this adds the package as a peer dependency of your project, which is rarely what you want.
( 07 )War story

React 18 Upgrade Breaks Material-UI Peer Dependency

Frontend Developerpnpm 8, React 18, Material-UI 4, TypeScript 4.5, Vite 4

Timeline

  1. 09:15Run 'pnpm add react@18 react-dom@18' to upgrade React in a large corporate dashboard project.
  2. 09:16pnpm install fails with 'ERR_PNPM_PEER_DEP_ISSUES' — lists @material-ui/core requires react@^16.8.0 || ^17.0.0.
  3. 09:20Check package.json: no overrides, strict-peer-dependencies=true (default).
  4. 09:25Run 'pnpm why @material-ui/core' — it's a direct dependency from package.json.
  5. 09:30Check Material-UI 4 docs — it only supports React up to 17. Need to upgrade to MUI 5.
  6. 09:35Run 'pnpm add @mui/material @mui/icons-material @emotion/react @emotion/styled' — all MUI 5 packages.
  7. 09:37pnpm install succeeds. But build fails: 'Module not found: Can't resolve @material-ui/core/styles' — several files still import from old MUI.
  8. 09:45Use codemod 'npx @mui/codemod v5.0.0/preset-safe' to migrate imports. Resolve 15 files manually.
  9. 10:00Build passes. Run 'pnpm ls react' — only one version (18.2.0). Peer conflict resolved.

I was tasked with upgrading React from 17 to 18 in a legacy dashboard app with 200+ components. The project used pnpm 8 with strict peer dependencies enabled. After running pnpm add for React 18, I immediately hit a peer dependency error: @material-ui/core v4.11.4 required react@^16.8.0 || ^17.0.0. pnpm refused to install because React 18 was outside that range.

I first tried adding an override in package.json to force @material-ui/core to accept React 18, but pnpm still reported the conflict because the peer range is checked at install time. I realized Material-UI 4 will never officially support React 18. The only fix was to upgrade to MUI 5, which supports React 18. I ran pnpm add for the new MUI packages and removed the old ones.

After the upgrade, the build failed because dozens of files still imported from @material-ui/core. I ran the MUI codemod to automate the import changes and manually fixed a few custom theme files. Finally, the build succeeded, and pnpm ls showed only one version of react. The lesson: peer dependency conflicts often force a major library upgrade, and you must plan for migration work beyond just fixing the version.

Root cause

Material-UI 4 specified a peer dependency range that excluded React 18. pnpm's strict resolution prevented the install.

The fix

Upgraded Material-UI to version 5, which supports React 18, and migrated all imports using codemod tools.

The lesson

Always check peer dependency ranges before upgrading a shared dependency like React. Use 'pnpm why' to trace which packages will break.

( 08 )How pnpm Resolves Peer Dependencies Differently

pnpm uses a content-addressable store and creates a flat node_modules structure, but it enforces peer dependency constraints at install time. Unlike npm, which installs peer dependencies automatically (since npm v6), pnpm requires you to explicitly declare them in your root package.json. This is because pnpm aims for strict isolation and reproducibility.

When pnpm resolves the dependency tree, it checks each package's peer dependencies against the versions available in the root. If a peer is missing or its version doesn't match, pnpm fails with an error. This strictness is controlled by 'strict-peer-dependencies' (default true) in .npmrc. Setting it to false will skip the check but can lead to runtime errors.

( 09 )Using pnpm Overrides and Resolutions

If you cannot upgrade a package but need to satisfy a peer dependency, you can use the 'pnpm.overrides' field in package.json. This forces a specific version of a package for all dependencies. For example: 'pnpm': { 'overrides': { 'react': '17.0.2' } }. Note that overrides only work for direct dependencies, not transitive ones in some cases.

Alternatively, you can use the 'resolutions' field (pnpm-specific) to force a version: 'resolutions': { 'react': '17.0.2' }. However, this overrides the entire tree and may break other packages. A better approach is to add the exact peer version needed: 'pnpm add <peer>@<version>' and then use 'pnpm dedupe' to flatten.

( 10 )Debugging Peer Conflicts in Workspaces (Monorepo)

In a pnpm workspace with multiple packages, peer dependency conflicts can become complex because each workspace package may have its own dependencies. The root pnpm-lock.yaml includes all packages. If two workspace packages require different versions of the same peer, pnpm may install both versions, but only one will be hoisted to the root. This can cause the 'multiple versions' warning.

To debug, use 'pnpm ls -r --depth Infinity' to see the tree for all packages. Look for the peer package appearing with different versions. The fix is to align the peer version requirements across workspace packages, often by using a shared devDependency at the root level or by using 'pnpm -w add' to add the peer to the root.

( 11 )Automated Detection with pnpm Audit and Why

Before upgrading a major dependency, run 'pnpm audit' to see if any packages have known peer issues. Also, use 'pnpm why <package>' to understand why a particular version is installed. For example, 'pnpm why react' will show every package that depends on react and their version ranges.

You can also run 'pnpm list --depth Infinity --json | jq '..|objects|select(.peerDependencies?)'' to extract all peer dependency requirements from the lockfile. This is useful for identifying potential conflicts before they cause install failures.

Frequently asked questions

What does 'ERR_PNPM_PEER_DEP_ISSUES' mean exactly?

It means one or more packages in your dependency tree have peer dependencies that are not satisfied by the versions installed in your project. pnpm lists the unsatisfied peers in the error message. You must add or update those peer dependencies in your root package.json to match the required ranges.

Should I set 'strict-peer-dependencies=false' to bypass the error?

Only as a temporary workaround for development. Disabling strict checking can hide real conflicts that manifest as runtime errors like 'Cannot find module' or undefined behavior. It's better to fix the root cause by adding missing peers or updating conflicting versions.

How do I add a peer dependency correctly in pnpm?

Use 'pnpm add <package>@<version>' to add it to your root package.json as a regular dependency (or devDependency if for development). There's no special 'peer' flag needed because pnpm treats all root dependencies as the source of truth for peers.

Can I have multiple versions of the same peer dependency?

pnpm tries to hoist a single version, but if two packages require incompatible ranges, pnpm may install multiple versions in nested node_modules. This is usually undesirable because it increases bundle size and can cause type conflicts. Use overrides or update packages to align versions.

Why does pnpm not auto-install peer dependencies like npm?

pnpm's design philosophy prioritizes strictness and reproducibility. Auto-installing peers can lead to unexpected package versions and breaks the principle that the lockfile fully represents the dependency tree. By requiring explicit declaration, pnpm ensures you are aware of and control peer dependencies.