An install stops with a wall of red:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm is not broken and neither is your project. Two packages disagree about which version of a shared dependency they need, and since npm 7 that disagreement stops the install instead of silently guessing. The error text names both sides of the argument — reading it carefully is most of the work.
Key Takeaways
- ERESOLVE means two packages require incompatible versions of the same peer dependency.
- The error block names the conflicting packages and versions; read it before applying any flag.
- –legacy-peer-deps restores npm 6 behaviour and installs anyway, which is a workaround rather than a resolution.
- –force is a blunter version of the same thing and is more likely to produce a broken node_modules.
- The overrides field in package.json is the durable fix because it is committed and applies to every install.
Quick Fix
Read the conflict block in the error output to see which two packages disagree and on what version. That tells you whether to upgrade one package, pin a version with overrides, or install with –legacy-peer-deps as a temporary measure.
npm install 2>&1 | head -40
Read the Conflict Before Reaching for a Flag
The useful part of the output looks like this:
npm ERR! While resolving: my-app@1.0.0
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR! react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.0" from some-old-library@2.1.0
Read it as a sentence: the project installed React 18, but some-old-library declares it only works with React 17. Now you know the actual decision in front of you — update the old library, downgrade React, or tell npm to proceed anyway.
If the block scrolls past, capture it:
npm install 2>&1 | head -40
Option 1: Update the Outdated Package (Best Outcome)
Peer conflicts usually mean one dependency has fallen behind. Check whether a newer release supports your version:
npm view some-old-library versions --json | tail -20
Then inspect the peer requirements of a candidate version:
npm view some-old-library@3.0.0 peerDependencies
If a newer version accepts React 18, upgrading resolves the conflict genuinely rather than suppressing it:
npm install some-old-library@latest
This is the only option that leaves you with a dependency tree npm considers valid, so try it first.
Option 2: Pin a Version With overrides
When the conflicting package is unmaintained but works fine in practice, force the resolution in package.json:
{
"overrides": {
"some-old-library": {
"react": "$react"
}
}
}
The $react syntax means “whatever version the root project uses”. Then reinstall cleanly:
rm -rf node_modules package-lock.json
npm install
This is the best durable fix short of upgrading, because it is committed to the repository. Every developer and every CI run gets the same resolution without needing to remember a flag.
Option 3: –legacy-peer-deps (Workaround)
This restores npm 6 behaviour: peer dependencies are ignored rather than enforced.
npm install --legacy-peer-deps
The install succeeds, and in many cases the app runs fine — peer ranges are often more conservative than reality. But you have silenced a warning rather than resolved it, and the mismatch can surface later as a confusing runtime error.
If you need it consistently, record it in the project so CI behaves like your laptop:
echo "legacy-peer-deps=true" >> .npmrc
Commit that file. An .npmrc that only exists on one machine is a classic source of “works locally, fails in CI”.
What About –force?
Avoid it. --force tells npm to ignore a broader set of conflicts and write whatever it can, which frequently produces duplicated packages and a node_modules that does not match your lockfile. If --legacy-peer-deps does not work, the honest conclusion is that the dependency genuinely conflicts and needs a version decision, not a bigger hammer.
When the Lockfile Is the Problem
If the error appeared without any dependency change — particularly after a branch merge — your lockfile may be inconsistent. Rebuild it from your declared dependencies:
rm -rf node_modules package-lock.json
npm install
This regenerates the lockfile, so versions may move within the ranges in package.json. Do it on a branch, run your tests, and review the resulting diff before merging.
In CI, use npm ci rather than npm install. It installs strictly from the lockfile and fails loudly when the two files disagree, which catches this class of problem at build time instead of in production.
Verify the Fix
Confirm the tree is coherent:
npm ls react
A clean tree prints one version. Several versions at different depths means duplicates were installed, which is common after using --force. Then check for known-broken combinations:
npm audit --audit-level=high
And finally build the project. A successful install proves nothing on its own if the app no longer compiles.
Prevent It From Recurring
Commit your lockfile — dependency drift between machines produces exactly this error. Pin your Node version with an .nvmrc so everyone resolves against the same npm. Use npm ci in CI. And when you add a dependency, glance at its peer requirements before installing:
npm view PACKAGE peerDependencies
Ten seconds there saves the conflict entirely.
Frequently Asked Questions
Is –legacy-peer-deps safe to use?
Usually, but it is a workaround. It installs packages whose declared peer requirements conflict, which works when the range was overly strict but can cause runtime errors when the incompatibility is real. Prefer upgrading the package or using overrides.
What is the difference between –force and –legacy-peer-deps?
–legacy-peer-deps ignores peer dependency conflicts specifically. –force ignores a much wider set of checks and can install duplicate or mismatched packages. Use –legacy-peer-deps if you need one of them.
Why did this start after upgrading npm?
npm 6 silently ignored peer dependency conflicts. npm 7 and later treat them as errors. The conflict existed before; the newer npm simply reports it instead of guessing.
Should I commit package-lock.json?
Yes. It pins the exact resolved versions so every machine and CI run installs the same tree. Most ERESOLVE errors that appear on one machine and not another come from a missing or stale lockfile.