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.npm explain <package> to trace the conflict chain,
then either npm update the parent or add "overrides" to package.json.--force or --legacy-peer-deps globally
— they hide real incompatibilities that surface as runtime errors. Never set
legacy-peer-deps=true in global .npmrc.--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]
resolutions must be in the root package.json for workspaces — inner package
resolutions are ignored for hoisted dependencies. [src3]node_modules and lockfile, then reinstall.
Stale lockfiles are the #1 cause of "override not working" reports. [src5]
npm overrides requires npm >= 8.3.0 — older versions silently ignore the
overrides field. [src2, src5]
| # | Error / Symptom | Likelihood | Diagnostic Command | Fix |
|---|---|---|---|---|
| 1 | ERESOLVE unable to resolve dependency tree |
~45% | 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% | npm explain <package> |
Upgrade Z to version supporting current X [src7] |
| 3 | npm WARN ERESOLVE overriding peer dependency |
~10% | npm ls <package> |
Review if override is intentional; may need overrides [src1]
|
| 4 | Invalid peer dependency after --legacy-peer-deps |
~8% | npx check-peer-dependencies |
Remove flag, fix root cause with version alignment [src6] |
| 5 | Yarn warning ... has unmet peer dependency |
~5% | yarn why <package> |
Add resolutions to package.json [src3]
|
| 6 | pnpm WARN ... requires peer but none installed |
~4% | pnpm why <package> |
Install missing peer or use pnpm.peerDependencyRules [src4] |
| 7 | Duplicate packages in bundle | ~3% | npm dedupe --dry-run |
Run npm dedupe or add overrides [src1]
|
| 8 | npm ci fails but npm install works |
Common | Check lockfile freshness | Regenerate: rm package-lock.json && npm install [src6] |
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?
│ │ │ │ │ ├── YES → `npm install <parent>@latest`
│ │ │ │ │ └── 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 with overrides
│ │ │ └── NO → Check `npm ls` for version conflicts
│ │ └── Error says "peer dep ... from ..."?
│ │ └── `npm explain <package>` → upgrade or override [src7]
│ ├── Yarn Classic (v1) or Yarn Berry (v2+)
│ │ └── Add `resolutions` to root package.json → `yarn install` [src3]
│ └── pnpm
│ └── Install missing peer or configure peerDependencyRules [src4]
└── Still failing?
└── Nuclear: rm -rf node_modules package-lock.json && npm cache clean --force && npm install [src6]
Run npm install and read the ERESOLVE output carefully. It tells you exactly which packages
conflict. [src6]
# 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 shows While resolving: [email protected] and
Could not resolve dependency: peer react@"^17.0.0" from [email protected].
Use npm explain (alias: npm why) to trace the dependency chain. [src5,
src6]
# 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.
Update the package that has the outdated peer dependency requirement. [src7]
# 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.
When a transitive dependency pins an incompatible version and no update is available. [src1, src5]
{
"dependencies": {
"some-library": "^2.0.0"
},
"overrides": {
"react": "^18.2.0",
"some-library": {
"old-subdep": "2.0.0"
}
}
}
# 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.
Yarn Classic and Berry both support resolutions in package.json. [src3]
{
"dependencies": {
"some-library": "^2.0.0"
},
"resolutions": {
"react": "18.2.0",
"**/lodash": "4.17.21",
"some-library/old-subdep": "2.0.0"
}
}
# Clean install after changing resolutions
rm -rf node_modules yarn.lock
yarn install
# Verify
yarn why react
pnpm provides granular control via pnpm.peerDependencyRules in package.json. [src4]
{
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": ["@babel/core"],
"allowedVersions": {
"react": "18"
},
"allowAny": ["eslint"]
},
"overrides": {
"lodash": "4.17.21"
}
}
}
# Clean install
rm -rf node_modules pnpm-lock.yaml
pnpm install
# Verify
pnpm why react
// Input: Library requires react@^17 but project uses react@18
// Output: Forces all packages to accept [email protected]
{
"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.
// Requires npm >= 8.3.0. [src1, src2]
# 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)
legacy-peer-deps=true
# Prefer deduplication when resolving (npm 8.13+)
prefer-dedupe=true
# Strict engine checks
engine-strict=true
#!/bin/bash
# Input: Run in project root with package.json
# Output: Conflict report with fix suggestions
echo "=== npm Dependency Conflict Diagnosis ==="
echo "npm version: $(npm --version)"
echo "node version: $(node --version)"
echo ""
echo "--- Peer dependency check ---"
npx check-peer-dependencies 2>/dev/null || echo "(install: npm i -g check-peer-dependencies)"
echo ""
echo "--- Duplicate packages ---"
npm ls --all 2>&1 | grep "deduped" | sort | uniq -c | sort -rn | head -10
echo ""
echo "--- Outdated packages ---"
npm outdated --long 2>/dev/null | head -20
echo ""
echo "--- Install dry run (conflicts) ---"
npm install --dry-run 2>&1 | grep -E "(ERESOLVE|peer|conflict|WARN)" | head -20
# BAD — hides real incompatibilities that cause runtime errors [src6, src7]
npm install --force
# or
npm config set legacy-peer-deps true # global — affects ALL projects!
# Silences the error without fixing the conflict.
# 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
# BAD — loses reproducibility, may introduce NEW conflicts [src6]
rm package-lock.json
npm install
# Different versions resolved every time. CI becomes non-deterministic.
# GOOD — only regenerate when you've actually changed overrides/versions
rm -rf node_modules package-lock.json
npm install
git add package-lock.json && git commit -m "Regenerate lockfile after override change"
// BAD — "*" means any version, including breaking majors [src1, src5]
{
"overrides": {
"lodash": "*"
}
}
// GOOD — explicit version, predictable behavior [src1, src5]
{
"overrides": {
"lodash": "4.17.21"
}
}
--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]overrides silently ignored on old npm: The overrides
field requires npm >= 8.3.0. Older versions skip it with no warning. CI runners often have stale npm
versions. [src2, src5]
resolutions ignored 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]overrides 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.peerDependencyRules.allowedVersions for intentional mismatches or
ignoreMissing for optional peers. [src4]npm ci ignores overrides not in lockfile: npm ci installs
from lockfile only. Changed overrides require regenerating package-lock.json
first via npm install. [src5,
src6]# === Identify conflicts ===
npm ls --all 2>&1 | head -100 # full dependency tree
npm explain <package-name> # trace dependency chain (alias: npm why)
npm outdated --long # list all outdated packages
npm install --dry-run 2>&1 | grep -E "ERESOLVE|peer|conflict"
# === Yarn equivalents ===
yarn why <package-name>
yarn list --pattern <package-name>
# === pnpm equivalents ===
pnpm why <package-name>
pnpm ls <package-name>
# === Fix commands ===
npm dedupe # reduce duplicate versions
npm dedupe --dry-run # preview changes
rm -rf node_modules package-lock.json # clean slate
npm cache clean --force # clear npm cache
npm install # fresh install
npx check-peer-dependencies # verify peer deps satisfied
# === Version checks ===
npm --version # need >= 8.3 for overrides
node --version # check engine 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 introduced | Breaking — many projects hit new errors [src6] |
| npm 8.3 (Dec 2021) | overrides field added |
Proper fix for transitive dependency 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 |
| npm 10.x (Sep 2023) | Current stable, ships with Node 20+ | overrides fully stable, improved error messages |
| Yarn Classic 1.x | resolutions always supported |
Simple version pinning [src3] |
| Yarn Berry 2-4 | resolutions + strict peer mode |
Stricter than npm; Plug'n'Play changes resolution [src3] |
| pnpm 7+ | Strict peer deps, peerDependencyRules |
Does not auto-install conflicting peers [src4] |
| pnpm 9.x (2024) | Current stable, enhanced overrides |
pnpm.overrides for version pinning [src4] |
| 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 | Use workspace-specific dependency ranges |
overrides vs yarn resolutions are NOT interchangeable:
npm uses overrides (npm >= 8.3), Yarn uses resolutions. Including both 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]"react": "^18.2.0" forces EVERY package in the tree to use React 18.2+, even packages not
tested with it. This can cause subtle runtime bugs. [src1, src5]
package-lock.json (npm),
yarn.lock (Yarn), pnpm-lock.yaml (pnpm) are NOT interchangeable. Mixing
package managers causes phantom conflicts. Enforce one via engines or corepack.
[src6]