npm ERESOLVE Unable to Resolve Dependency Tree: Fix

ERESOLVE means a package's peer range, usually React, doesn't match your version. Upgrade that package, add a scoped override, or use --legacy-peer-deps last.
Since React 19 came out, this has become one of the most common npm errors. Somebody runs npm install on a Next.js 15 or 16 project, adds an editor or a chart library, and gets a wall of red. The usual advice online is "just add --force". Sometimes that's fine. Sometimes it ships a library that crashes the page in production. That happened on this very site: the rich text editor we used, react-quill, declares support for React 16 to 18 only, and on React 19 it didn't just warn, it broke. So before you force anything, take two minutes to read what npm is telling you.
Key takeaways
- The error names the package that's out of date in the "Could not resolve dependency" line. Start there.
- Best fix: upgrade that package to a version that supports your React (check its changelog).
- Second best: an
overridesentry inpackage.json, scoped to that one package. --legacy-peer-depsignores all peer ranges in the project, and--forceinstalls whatever it gets. Both hide the problem instead of fixing it.- If you do use a flag, put it in a committed
.npmrc, ornpm cifails in CI and on the server.
How to read the error
Here's a real one from a React 19 project (npm 10 and newer print npm error; older versions print npm ERR!):
npm error code ERESOLVE npm error ERESOLVE unable to resolve dependency tree npm error npm error While resolving: my-app@0.1.0 npm error Found: react@19.2.0 npm error node_modules/react npm error react@"^19.2.0" from the root project npm error npm error Could not resolve dependency: npm error peer react@"^16 || ^17 || ^18" from react-quill@2.0.0 npm error node_modules/react-quill npm error react-quill@"^2.0.0" from the root project
Only three lines matter:
Found: react@19.2.0is what you have.peer react@"^16 || ^17 || ^18"is what the package says it supports.from react-quill@2.0.0is the package that's behind.
So the problem isn't "npm is broken". One package hasn't said it supports React 19 yet. The question is whether it actually works on React 19 anyway. Sometimes the range is just old and the code is fine. Sometimes the package uses an API React 19 removed, like findDOMNode or string refs, and it will crash.
Fix 1: Upgrade the package (do this first)
npm view react-quill peerDependencies npm view react-quill versions --json | tail -n 5
If a newer version supports your React, install it and you're done. For popular packages that's usually the case now. If the package is abandoned (react-quill's last release was in 2022), look for the maintained fork or a replacement. For react-quill that's react-quill-new. We ended up rendering stored HTML without the editor library on public pages, which was less code anyway.
Fix 2: Override the peer range for one package
If you've tested the package on your React version and it works, tell npm so, for that package only:
{
"dependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0",
"some-chart-lib": "^3.1.0"
},
"overrides": {
"some-chart-lib": {
"react": "$react",
"react-dom": "$react-dom"
}
}
}
$react means "whatever version the root project uses", so you don't have to update the override when you upgrade React. Delete node_modules and package-lock.json once, run npm install, and commit the new lockfile. I prefer this to a global flag because it's written down, it's limited to one package, and you can delete it once the library catches up.
Fix 3: --legacy-peer-deps (when you're in a hurry)
npm install --legacy-peer-deps
This makes npm behave like npm 6: peer dependencies aren't installed automatically and conflicts are ignored, for every package in the tree. It works, and it's what most tutorials say. The catch is that it also hides the next conflict you'll introduce, and if you forget it on the server, the deploy fails there. If you use it, make it permanent and visible:
echo "legacy-peer-deps=true" >> .npmrc git add .npmrc
That file is read by npm install, npm ci, GitHub Actions and your Docker build, so they all resolve the tree the same way.
What about --force?
--force is different. It doesn't ignore peers; it installs the conflicting versions anyway and may fetch duplicate copies. Two copies of React in one bundle gives you the famous "Invalid hook call" error at runtime. I don't use --force for peer conflicts.
When it only fails in CI or on the server
Works on your laptop, fails in GitHub Actions with ERESOLVE. Three usual reasons:
- You installed locally with
--legacy-peer-depsbut didn't commit an.npmrc. CI runsnpm ciwithout the flag. - A different npm version. npm 7 and newer install peer dependencies; npm 6 didn't. Pin Node in CI with
actions/setup-nodeto the same major version you use locally. - The lockfile is out of date.
npm cirefuses to touch it. Runnpm installlocally and commitpackage-lock.json.
pnpm and Bun don't stop on this by default. pnpm prints "unmet peer" warnings and keeps going, Bun ignores them. That doesn't mean the package works, only that you'll find out at runtime. Run your app and click through the page that uses it.
Check it actually works
npm ls react # should show ONE react version, deduped everywhere npm run build npm start # open the page that uses the package
If npm ls react shows two different versions, fix that before shipping. That's the "Invalid hook call" bug waiting to happen.
The same fix in Yarn and pnpm
If you use another package manager, the override looks a little different. Yarn uses resolutions in package.json, for example "resolutions": { "react-quill/react": "19.2.0" }. pnpm can relax a single peer range without forcing anything else:
"pnpm": {
"peerDependencyRules": {
"allowedVersions": { "react": "19" }
}
}
Same rule as with npm: write it down in package.json, keep it as narrow as you can, and delete it when the package catches up.
Frequently asked questions
Is --legacy-peer-deps safe?
It's safe to install, but it turns off peer dependency checks for the whole project. Use it when you've confirmed the packages work, commit it in .npmrc, and prefer a scoped overrides entry when only one package is the problem.
What's the difference between --force and --legacy-peer-deps?
--legacy-peer-deps ignores peer dependencies. --force installs conflicting versions anyway and can put two copies of a package, like React, in your app. For peer conflicts, --legacy-peer-deps or overrides is the safer choice.
Why do I get ERESOLVE after upgrading to React 19?
Many libraries still list react@"^16 || ^17 || ^18" as their peer range. Upgrade those libraries, replace abandoned ones, or override their peer range after testing them on React 19.
How do I fix ERESOLVE in GitHub Actions?
Commit an .npmrc with the same setting you used locally, commit an up-to-date package-lock.json, and use the same Node major version in CI as on your machine.
Dependency hell blocking a release?
I untangle React 19 and Next.js upgrades, replace abandoned packages and get builds green again in CI. Book my bug fix service for React, Next.js and Node.js, see my web development services, or contact me with the full error output. If the build gets past npm and then runs out of memory, read how to fix JavaScript heap out of memory in next build.
Written by
MD Rakibul Islam Rakib
Full-stack developer, DevOps engineer and Linux system administrator with 5+ years of production experience. I deploy, harden and fix servers and web apps for clients worldwide, and everything in this article runs on real servers I manage, including this site.
- npm eresolve
- unable to resolve dependency tree
- legacy-peer-deps
- react 19 peer dependency
- npm overrides


