---
# === IDENTITY ===
id: software/debugging/npm-dependency-conflicts/2026
canonical_question: "How do I resolve npm and yarn dependency conflicts?"
aliases:
  - "npm ERESOLVE unable to resolve dependency tree"
  - "npm peer dependency conflict fix"
  - "npm install upstream dependency conflict"
  - "yarn dependency resolution conflict"
  - "npm --legacy-peer-deps vs --force"
  - "npm overrides package.json"
  - "pnpm peer dependency error"
  - "npm ERR ERESOLVE could not resolve"
  - "fix npm conflicting peer dependency"
  - "npm dedupe dependency conflicts"
  - "npm ERR! Cannot read properties of null (reading 'edgesOut')"
entity_type: software_reference
domain: software > debugging > npm_dependency_conflicts
region: global
jurisdiction: global
temporal_scope: 2021-2026

# === VERIFICATION ===
last_verified: 2026-05-17
confidence: 0.93
version: 1.1
first_published: 2026-02-20

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: "npm 7.0.0 (2020-10) — peer deps installed by default, ERESOLVE errors introduced"
  next_review: 2026-11-13
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Never recommend --force or --legacy-peer-deps as a first solution — always diagnose with npm ls and npm explain first"
  - "npm overrides only works in root package.json — nested/workspace overrides are ignored"
  - "Yarn resolutions must be in root package.json for workspaces — inner package resolutions are ignored for hoisted deps"
  - "pnpm strict peer mode (default since v8) cannot be overridden per-package — only via .npmrc peerDependencyRules"
  - "npm 7+ enforces peer deps by default — npm 6 and earlier silently ignored them"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Error is during webpack/vite/tsc build, not npm/yarn install"
    use_instead: "software/debugging/webpack-vite-build-failures/2026"
  - condition: "Error is TypeScript compilation type mismatch, not package resolution"
    use_instead: "software/debugging/typescript-compilation-errors/2026"
  - condition: "Using Deno or Bun"
    use_instead: "Different package resolution — this unit is npm/yarn/pnpm only"
  - condition: "Error is node-gyp build failure during install"
    use_instead: "Native module compilation issue, not dependency conflict"

# === AGENT HINTS ===
inputs_needed:
  - key: "package_manager"
    question: "Which package manager are you using?"
    type: choice
    options: ["npm", "yarn classic (v1)", "yarn berry (v2+)", "pnpm"]
  - key: "error_type"
    question: "What error are you seeing?"
    type: choice
    options: ["ERESOLVE unable to resolve dependency tree", "peer dep conflict on install", "version mismatch after install", "lockfile conflict"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/debugging/npm-dependency-conflicts/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-05-17)"

# === BUY LINKS ===
# (none — software_reference cards do not carry buy_links)

# === RELATED UNITS ===
related_kos:
  related_to:
    - id: "software/debugging/nextjs-build-failures/2026"
      label: "Next.js Build Failures"
    - id: "software/debugging/webpack-vite-build-failures/2026"
      label: "webpack and Vite Build Failures"
    - id: "software/debugging/typescript-compilation-errors/2026"
      label: "TypeScript Compilation Errors"
  often_confused_with:
    - id: "software/debugging/webpack-vite-build-failures/2026"
      label: "webpack/Vite Build Failures (compile-time, not install-time)"

# === SOURCES (7 authoritative sources) ===
sources:
  - id: src1
    title: "npm Docs — package.json overrides"
    author: npm, Inc.
    url: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides
    type: official_docs
    published: 2024-01-01
    reliability: authoritative
  - id: src2
    title: "npm RFC 0036 — Overrides"
    author: npm, Inc.
    url: https://github.com/npm/rfcs/blob/main/accepted/0036-overrides.md
    type: official_docs
    published: 2021-12-01
    reliability: authoritative
  - id: src3
    title: "Yarn Docs — Selective Dependency Resolutions"
    author: Yarn Contributors
    url: https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/
    type: official_docs
    published: 2023-01-01
    reliability: authoritative
  - id: src4
    title: "pnpm Docs — How Peers Are Resolved"
    author: pnpm Contributors
    url: https://pnpm.io/how-peers-are-resolved
    type: official_docs
    published: 2024-01-01
    reliability: authoritative
  - id: src5
    title: "HeroDevs — A Guide to NPM Overrides"
    author: HeroDevs
    url: https://www.herodevs.com/blog-posts/a-guide-to-npm-overrides-take-control-of-your-dependencies
    type: technical_blog
    published: 2024-08-01
    reliability: high
  - id: src6
    title: "Fix npm ERR! ERESOLVE unable to resolve dependency tree"
    author: OpenReplay
    url: https://blog.openreplay.com/fix-npm-err-eresolve-dependency/
    type: technical_blog
    published: 2024-06-01
    reliability: high
  - id: src7
    title: "How to Fix npm Peer Dependency Conflicts"
    author: OneUptime
    url: https://oneuptime.com/blog/post/2026-01-22-nodejs-fix-npm-peer-dependency-conflicts/view
    type: technical_blog
    published: 2026-01-22
    reliability: high
---

# How Do I Resolve npm and Yarn Dependency Conflicts?

## How do I resolve npm and yarn dependency conflicts?

## TL;DR

- **Bottom line**: Most npm/yarn dependency conflicts are caused by incompatible peer dependency versions. The proper fix is to align versions via `npm ls`, `npm explain`, and targeted upgrades. Use `overrides` (npm) or `resolutions` (yarn) for transitive dependency pinning. `--legacy-peer-deps` and `--force` are escape hatches, not solutions.
- **Key tool/command**: `npm ls <package>` to identify the conflict, then `npm explain <package>` to understand why each version is required, then either upgrade or add an `overrides` entry in package.json.
- **Watch out for**: Using `--force` or `--legacy-peer-deps` globally — they hide real incompatibilities that will surface as runtime errors. Never set `legacy-peer-deps=true` in global `.npmrc`.
- **Works with**: npm 7+ (ERESOLVE enforcement), npm 8.3+ (overrides support), Yarn Classic v1 (resolutions), Yarn Berry v2+ (resolutions), pnpm 7+ (peerDependencies strict mode).

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- Never recommend `--force` or `--legacy-peer-deps` as a first solution — always diagnose the conflict first with `npm ls` and `npm explain`. [src6]
- `overrides` only works in the root package.json — nested/workspace overrides are ignored by npm. [src1, src5]
- Yarn `resolutions` must be in the root package.json for workspaces — inner package resolutions are ignored for hoisted dependencies. [src3]
- After any override/resolution change, delete `node_modules` and lockfile, then reinstall. Stale lockfiles are the #1 cause of "override not working" reports. [src5]
- pnpm does NOT auto-install conflicting peer dependencies — it prints a warning and skips them. You must manually choose a version. [src4]
- `npm overrides` requires npm >= 8.3.0 — older versions silently ignore the `overrides` field. [src2, src5]

## Quick Reference

| # | Error / Symptom | Likelihood | Diagnostic Command | Fix |
|---|---|---|---|---|
| 1 | `ERESOLVE unable to resolve dependency tree` | ~45% of cases | `npm install 2>&1 \| head -50` | Read conflict, align versions or add `overrides` [src6] |
| 2 | `Could not resolve dependency: peer X@^Y from Z` | ~25% of cases | `npm explain <package>` | Upgrade Z to version supporting current X [src7] |
| 3 | `npm WARN ERESOLVE overriding peer dependency` | ~10% of cases | `npm ls <package>` | Review if override is intentional; may need `overrides` [src1] |
| 4 | `Invalid peer dependency` after `--legacy-peer-deps` | ~8% of cases | `npx check-peer-dependencies` | Remove flag, fix root cause with version alignment [src6] |
| 5 | Yarn `warning ... has unmet peer dependency` | ~5% of cases | `yarn why <package>` | Add `resolutions` to package.json [src3] |
| 6 | pnpm `WARN ... requires peer ... but none was installed` | ~4% of cases | `pnpm why <package>` | Install missing peer or use `pnpm.peerDependencyRules` [src4] |
| 7 | Duplicate packages in bundle (different versions) | ~3% of cases | `npm ls <package>` or `npm dedupe --dry-run` | Run `npm dedupe` or add `overrides` to force single version [src1] |
| 8 | `npm ci` fails but `npm install` works | Common in CI | Check lockfile freshness | Regenerate: `rm package-lock.json && npm install` [src6] |

## Decision Tree

```
START — npm/yarn install fails with dependency conflict
├── Which package manager?
│   ├── npm 7+
│   │   ├── Error says "ERESOLVE unable to resolve dependency tree"?
│   │   │   ├── YES → Run `npm explain <conflicting-package>` [src6]
│   │   │   │   ├── Can you upgrade the parent package to support the newer peer?
│   │   │   │   │   ├── YES → `npm install <parent>@latest` → done
│   │   │   │   │   └── NO → Add `overrides` to package.json [src1, src5]
│   │   │   │   └── Is this a dev-only tool (linter, test runner)?
│   │   │   │       ├── YES → `--legacy-peer-deps` is acceptable [src6]
│   │   │   │       └── NO → Fix properly with overrides
│   │   │   └── NO → Check `npm ls` for version tree conflicts
│   │   └── Error says "peer dep ... from ..."?
│   │       └── `npm explain <package>` → upgrade or override [src7]
│   ├── Yarn Classic (v1)
│   │   └── Add `resolutions` to root package.json → `yarn install` [src3]
│   ├── Yarn Berry (v2+)
│   │   └── Add `resolutions` to root package.json → `yarn install` [src3]
│   └── pnpm
│       └── Install missing peer manually or configure peerDependencyRules [src4]
└── Still failing?
    └── Nuclear option: rm -rf node_modules package-lock.json && npm cache clean --force && npm install [src6]
```

## Decision Logic

### If the install error contains `ERESOLVE unable to resolve dependency tree`
--> Run `npm explain <conflicting-package>` to identify the parent and its peer requirement. Upgrade the parent to a version that supports the current peer if possible. [src6, src7]

### If no upgrade path exists for the conflicting parent package
--> Add an `overrides` (npm ≥ 8.3) or `resolutions` (yarn / pnpm) block in the root `package.json` pinning the desired version, then delete `node_modules` + lockfile and reinstall. [src1, src3, src5]

### If the conflict is in a dev-only tool (linter, test runner, formatter)
--> `--legacy-peer-deps` is an acceptable short-term workaround because the package is not shipped at runtime. Still prefer a proper override for reproducibility. [src6]

### If running pnpm and seeing `requires peer ... but none was installed`
--> pnpm does not auto-install conflicting peers. Either install the missing peer explicitly or configure `pnpm.peerDependencyRules.allowedVersions` / `ignoreMissing` in `package.json`. [src4]

### If `npm ci` fails on CI but `npm install` works locally
--> The lockfile is out of sync with `overrides` or `package.json`. Locally run `rm -rf node_modules package-lock.json && npm install`, commit the regenerated lockfile, then rerun CI. [src5, src6]

### If you must use `--force` to install
--> Treat this as a diagnostic signal, not a fix. `--force` bypasses cache, checksum AND peer checks — strictly weaker than `--legacy-peer-deps`. Find the real conflict via `npm explain` and add a proper override before merging. [src6]

### If the project uses workspaces (npm / yarn / pnpm monorepo)
--> Place `overrides` / `resolutions` in the ROOT `package.json` only. Workspace-member overrides are ignored for hoisted dependencies. After editing, do a full clean reinstall from the workspace root. [src1, src3]

## Step-by-Step Guide

### 1. Identify the conflicting packages

Run `npm install` and read the ERESOLVE output carefully. It tells you exactly which packages conflict. [src6]

```bash
# See the full error (npm truncates by default)
npm install 2>&1 | head -80

# Or use verbose mode for maximum detail
npm install --verbose 2>&1 | grep -A 5 "ERESOLVE"
```

**Verify**: The error output shows lines like `While resolving: package-a@1.0.0` and `Could not resolve dependency: peer react@"^17.0.0" from package-b@2.0.0`.

### 2. Understand why each version is required

Use `npm explain` (alias: `npm why`) to trace the dependency chain. [src5, src6]

```bash
# Show which packages depend on react and what versions they require
npm explain react

# Tree view of all installed versions
npm ls react

# Check for all outdated packages
npm outdated
```

**Verify**: `npm explain react` shows each dependant with its required version range, e.g., `react@"^18.0.0" from @testing-library/react@14.0.0`.

### 3. Attempt version alignment (preferred fix)

Update the package that has the outdated peer dependency requirement. [src7]

```bash
# Update a specific package to its latest version
npm install @testing-library/react@latest

# Update all packages to latest compatible versions
npm update

# Check what would change without modifying anything
npm update --dry-run
```

**Verify**: `npm ls react` shows a single version with no `UNMET PEER DEPENDENCY` warnings.

### 4. Use overrides for npm (when alignment is impossible)

When a transitive dependency pins an incompatible version and no update is available. [src1, src5]

```json
{
  "dependencies": {
    "some-library": "^2.0.0"
  },
  "overrides": {
    "react": "^18.2.0",
    "some-library": {
      "old-subdep": "2.0.0"
    }
  }
}
```

```bash
# After adding overrides, always clean install
rm -rf node_modules package-lock.json
npm install

# Verify the override took effect
npm ls old-subdep
npm explain old-subdep
```

**Verify**: `npm ls old-subdep` shows only the overridden version.

### 5. Use resolutions for Yarn

Yarn Classic and Berry both support `resolutions` in package.json. [src3]

```json
{
  "dependencies": {
    "some-library": "^2.0.0"
  },
  "resolutions": {
    "react": "18.2.0",
    "**/lodash": "4.17.21",
    "some-library/old-subdep": "2.0.0"
  }
}
```

```bash
# Clean install after changing resolutions
rm -rf node_modules yarn.lock
yarn install

# Verify
yarn why react
yarn why old-subdep
```

**Verify**: `yarn why react` shows the pinned version is used by all dependants.

### 6. Configure pnpm peer dependency rules

pnpm provides granular control via `pnpm.peerDependencyRules` in package.json. [src4]

```json
{
  "pnpm": {
    "peerDependencyRules": {
      "ignoreMissing": ["@babel/core"],
      "allowedVersions": {
        "react": "18"
      },
      "allowAny": ["eslint"]
    },
    "overrides": {
      "lodash": "4.17.21"
    }
  }
}
```

```bash
# Clean install
rm -rf node_modules pnpm-lock.yaml
pnpm install

# Verify
pnpm why react
pnpm ls react
```

**Verify**: `pnpm why react` shows the correct version without peer warnings.

## Code Examples

### package.json: npm overrides for React peer conflict

```json
// Input:  Library requires react@^17 but project uses react@18
// Output: Forces all packages to accept react@18.2.0

{
  "name": "my-app",
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "legacy-component-lib": "^3.0.0"
  },
  "overrides": {
    "react": "$react",
    "react-dom": "$react-dom"
  }
}
// Note: "$react" references the version in your own dependencies.
// This ensures overrides always match your direct dependency version.
// Requires npm >= 8.3.0. [src1, src2]
```

### .npmrc: project-level configuration for persistent flags

```ini
# Input:  Project that must use --legacy-peer-deps on every install
# Output: Flag applied automatically without passing it each time

# .npmrc (place in project root, commit to git)
# Only use this for projects where peer dep alignment is impossible
legacy-peer-deps=true

# Prefer deduplication when resolving (npm 8.13+)
prefer-dedupe=true

# Strict engine checks (catch Node.js version mismatches early)
engine-strict=true
```

### Bash: automated dependency conflict diagnosis script

> Full script: [bash-automated-dependency-conflict-diagnosis-scrip.sh](scripts/bash-automated-dependency-conflict-diagnosis-scrip.sh) (28 lines)

```bash
#!/bin/bash
# Input:  Run in project root with package.json
# Output: Conflict report with actionable fix suggestions
echo "=== npm Dependency Conflict Diagnosis ==="
echo "npm version: $(npm --version)"
# ... (see full script)
```

## Anti-Patterns

### Wrong: Using --force or --legacy-peer-deps as default

```bash
# BAD — hides real incompatibilities that cause runtime errors [src6, src7]
npm install --force
# or
npm config set legacy-peer-deps true  # global setting — affects ALL projects!

# This installs incompatible packages that may crash at runtime.
# You've silenced the error, not fixed the conflict.
```

### Correct: Diagnose first, then fix the root cause

```bash
# GOOD — understand the conflict, then fix it [src5, src6]
npm explain react            # see why each version is needed
npm install some-lib@latest  # update the conflicting package
# If no update available:
# Add "overrides" to package.json (npm 8.3+)
```

### Wrong: Deleting package-lock.json on every conflict

```bash
# BAD — loses reproducibility, may introduce NEW conflicts [src6]
rm package-lock.json
npm install
# Different versions resolved every time.
# CI builds become non-deterministic.
```

### Correct: Targeted lockfile regeneration

```bash
# GOOD — only regenerate when you've actually changed overrides/versions
# After modifying overrides or dependency versions in package.json:
rm -rf node_modules package-lock.json
npm install
# Then commit the new package-lock.json immediately.
git add package-lock.json && git commit -m "Regenerate lockfile after override change"
```

### Wrong: Using wildcard overrides without version constraint

```json
{
  "overrides": {
    "lodash": "*"
  }
}
```

```bash
# BAD — "*" means any version, including breaking majors [src1, src5]
# npm may resolve to lodash@5.0.0-beta which breaks your code
```

### Correct: Pin to specific version or range in overrides

```json
{
  "overrides": {
    "lodash": "4.17.21"
  }
}
```

```bash
# GOOD — explicit version, predictable behavior [src1, src5]
# Or use a range: "lodash": "^4.17.21"
```

## Common Pitfalls

- **`--legacy-peer-deps` masks runtime crashes**: The flag installs packages that declare they need React 17 alongside your React 18. The package may call React 17-only APIs and crash at runtime. Always test thoroughly after using this flag. [src6]
- **npm `overrides` silently ignored on old npm**: The `overrides` field requires npm >= 8.3.0. Older versions skip it entirely with no warning. Run `npm --version` to verify. CI runners often have stale npm versions. [src2, src5]
- **Yarn `resolutions` not applied in workspace inner packages**: Resolutions must be in the root package.json. A `resolutions` field in a workspace member's package.json is ignored for hoisted dependencies. [src3]
- **Stale lockfile after override change**: Adding an `overrides` or `resolutions` entry without deleting `node_modules` and the lockfile means the override is not applied. Always `rm -rf node_modules package-lock.json && npm install`. [src5]
- **pnpm strict mode rejects ALL peer mismatches**: pnpm does not install conflicting peers at all by default. Use `pnpm.peerDependencyRules.allowedVersions` for intentional mismatches, or `ignoreMissing` for optional peers. [src4]
- **`npm ci` ignores overrides that are not in lockfile**: `npm ci` installs from lockfile only. If you changed `overrides` but didn't regenerate `package-lock.json`, `npm ci` uses the old resolutions. Always run `npm install` locally, then commit the lockfile before CI. [src5, src6]

## Diagnostic Commands

> Full script: [diagnostic-commands.sh](scripts/diagnostic-commands.sh) (29 lines)

```bash
# === Identify conflicts ===
# Full dependency tree (shows duplicates and unmet peers)
npm ls --all 2>&1 | head -100
# Why is this specific package installed? (trace dependency chain)
npm explain <package-name>
# ... (see full script)
```

## Version History & Compatibility

| Version / Tool | Change | Impact |
|---|---|---|
| npm 6.x | Peer deps NOT auto-installed, warnings only | No ERESOLVE errors; conflicts were silent [src6] |
| npm 7.0 (Oct 2020) | Peer deps auto-installed, ERESOLVE errors introduced | Breaking — many projects hit new errors on upgrade [src6] |
| npm 8.3 (Dec 2021) | `overrides` field added to package.json | Proper fix for transitive dep conflicts [src1, src2] |
| npm 8.13 (Jun 2022) | `--prefer-dedupe` flag added | Reduces duplicate versions during install |
| npm 9.x (Oct 2022) | Lockfile v3, stricter resolution | Better conflict detection, some new edge cases |
| npm 10.x (Sep 2023) | Current stable, ships with Node 20+ | `overrides` fully stable, improved error messages |
| Yarn Classic 1.x | `resolutions` in package.json (always supported) | Simple and reliable version pinning [src3] |
| Yarn Berry 2-4 | `resolutions` + strict peer mode by default | Stricter than npm; Plug'n'Play changes resolution [src3] |
| pnpm 7+ | Strict peer deps, `peerDependencyRules` config | Does not auto-install conflicting peers [src4] |
| pnpm 9.x (2024) | Current stable, enhanced `overrides` support | `pnpm.overrides` in package.json for version pinning [src4] |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| `npm install` fails with ERESOLVE | Package is fundamentally incompatible with your stack | Switch to an alternative package |
| Need to pin a transitive dependency version | You can upgrade the direct dependency to resolve the conflict | `npm update <package>` |
| Security patch for nested dependency | Override would change major version with breaking API | Wait for upstream fix or fork |
| CI builds fail on peer dep warnings | `--legacy-peer-deps` is already set globally | Remove global flag, fix per-project |
| Monorepo with shared dependencies | Each workspace needs a different version of the same package | Use workspace-specific dependency ranges |

## Important Caveats

- **npm `overrides` vs yarn `resolutions` are NOT interchangeable**: npm uses `overrides` (npm >= 8.3), Yarn uses `resolutions`. Including both in package.json is allowed but each tool only reads its own field. [src1, src3]
- **`--force` and `--legacy-peer-deps` do different things**: `--force` bypasses ALL safety checks (cache, checksums, peer deps). `--legacy-peer-deps` ONLY reverts peer dep behavior to npm 6 style. Always prefer `--legacy-peer-deps` if you must use a flag. [src6]
- **Overrides apply to the entire dependency tree**: An override like `"react": "^18.2.0"` forces EVERY package in the tree to use React 18.2+, even packages that have not been tested with it. This can cause subtle runtime bugs. [src1, src5]
- **pnpm resolves peers differently than npm/yarn**: pnpm may create multiple copies of the same package version, each with different peer dependency sets. This is by design and usually correct, but can cause confusion when inspecting node_modules. [src4]
- **Lock files are package-manager specific**: `package-lock.json` (npm), `yarn.lock` (Yarn), `pnpm-lock.yaml` (pnpm) are NOT interchangeable. Mixing package managers in a team causes phantom conflicts. Enforce one via `engines` field or `corepack`. [src6]

## Related Units

- [Next.js Build Failures](/software/debugging/nextjs-build-failures/2026)
- [webpack and Vite Build Failures](/software/debugging/webpack-vite-build-failures/2026)
- [TypeScript Compilation Errors](/software/debugging/typescript-compilation-errors/2026)
