Denly

Fix npm ERESOLVE and peer dependency conflicts

Updated 2026-11-03

npm exits with ERESOLVE when it cannot build a dependency tree that satisfies the ranges it was given. Since npm 7, peer dependencies are part of that tree. --legacy-peer-deps ignores them. npm does not recommend that, and it does not repair a normal version conflict.

npm’s config reference is the source for the two flags people mix up. legacy-peer-deps makes npm ignore peerDependencies while it builds the tree, which is what npm 3 through 6 did. strict-peer-deps does the opposite: every peer conflict becomes an install failure, including ones npm would otherwise resolve with a warning. The default sits between them. A conflict in a nested dependency can be overridden by the nearest non-peer specification, and npm prints a warning. A conflict caused by a direct dependency of your project fails with ERESOLVE.

Read the ERESOLVE report before you add a flag

From the directory that contains package.json:

Let the install fail, then inspect
npm --version
npm install
npm ls the-package

Replace the-package with the name in the error. A failed resolve does not rewrite your lockfile. Read three lines out of the report: which package declared the requirement, the range it declared, and the version npm found. npm ls shows every copy and which parent pulled it in. If React appears twice, write down both versions. Two copies are how a generated app later hits an invalid hook call, and a flag will not merge them.

You can also ask the registry what a release expects, without installing it:

The peer range a release publishes
npm view react-dom@19 peerDependencies

Use the package and version from your report. The answer is the contract you are being asked to meet. It is not a suggestion from the chat that generated the app.

Separate peer conflicts from other install failures

--legacy-peer-deps changes peer handling. Ordinary dependencies can coexist at different versions in a nested tree, as npm’s dependency-layout example shows. The flag does not repair unrelated install failures. Read the actual error before changing ranges.

What the report describesWhat to do
A peerDependencies range your direct dependency does not satisfyAlign your direct dependency, or upgrade the package that declared the peer. The flag is a last resort, below.
A nested peer conflict, and your own dependencies already agreeThe default may already install and print a warning. --strict-peer-deps turns that warning into ERESOLVE. Drop the strict flag before you add a second one.
No peer is mentionedDo not add --legacy-peer-deps. Diagnose the reported error first, such as an unavailable release or registry access failure. If you were chasing an advisory, follow what to do when npm audit fix changes nothing.
You also passed --omit=peerThat is a different setting. npm still designs a tree where the peers could sit correctly, then skips unpacking them. It does not ignore a conflict.

Align the packages your app actually imports

Install the pair the app loads, at versions whose ranges agree. React and React DOM are the usual pair in a Lovable, Bolt, or Vite app. The same shape works for any other pair the report names: one command, both packages, then the lockfile.

One agreed pair, then the tree
npm install react@19 react-dom@19
npm ls react react-dom

Use 18 on both sides if you are staying on React 18. Do not leave react on 18 and react-dom on 19 because one of them was already in the tree. Commit package.json and the lockfile together. Run the test script and a production build. If the app is Next.js, the framework’s own peer range decides whether React 19 is allowed. Check it with npm view next@YOUR_VERSION peerDependencies.react before you install, and use the Next.js 16 checklist when you are moving Next itself. Early Next.js 15.0.0 accepted React 18.2 or a React 19 release candidate, not the stable 19 line. Later 15 releases and current 16 releases also accept ^19.0.0. Your installed version is the one that counts.

When the stubborn package is not a direct dependency, a root overrides entry can pin it. The audit guide shows the shape, including the nested form that applies under one parent only. An override is still a version you have to run. It is not a way to silence ERESOLVE with a number you have not imported.

Use legacy-peer-deps only for a reviewed mismatch

npm’s own sentence is to not recommend the flag, because it will not enforce the peer contract that other packages may rely on. The reason it exists is narrower: a peer range that is too strict for you to move forward. That is a temporary project setting, after you have started the app on that combination and the tests you have still pass.

Put it in the project .npmrc, which npm reads for every install in that directory, including CI:

Project .npmrc, not your home directory
legacy-peer-deps=true

Do not run npm config set legacy-peer-deps true. That writes the user config, and the next unrelated repository skips the check as well. A one-off npm install --legacy-peer-deps is easy to forget on the next machine. Put the line in the project .npmrc when every install, including CI, should use it. Otherwise the next clean install can fail with the same ERESOLVE.

Leave the flag off in these cases:

  • The packages are loaded together. Hiding a React 18 and React DOM 19 split installs a tree that fails when the page renders.
  • You are moving to React 19 and a library still calls an API that release removed. The install is the wrong layer. Upgrade or replace the library, using the React 19 checklist.
  • You wanted a security fix. The flag does not select a patched version. --force is not the substitute: npm’s force setting allows conflicting peers in the root project and also drops other protections, including engine checks and the rule that npm audit fix stays inside your ranges. npm says not to use it unless you know what you want.

Remove the flag and reinstall cleanly

When the package publishes a range that accepts your version, delete the line from .npmrc and install again with no peer flag.

The install that should succeed on its own
npm install
npm ls --all
npm test
npm run build

npm ls --all checks the full installed tree, including nested peers. Bare npm ls defaults to depth zero and can miss those conflicts; see npm’s depth setting. An invalid line means the flag was hiding the conflict, not that the tree is finished. Fix that package, or put the setting back and write in the commit message which peer you accepted and why. A generated app that keeps the flag forever will collect the next incompatible major without telling you.

For weekly upkeep, you can manually create a recurring dependency-review task with Denly’s task schedules after connecting a project and runner. Configure its instructions and review gates before enabling it. The public report form below creates a report; it does not create a schedule or a pull request.

Commands and product behavior on this page were checked against the vendor documentation linked here on 3 November 2026. Those products change their screens. If a label has moved, follow the linked page rather than a memory of this one.

Free, no account

Check this repository

Paste a public GitHub URL. Denly checks supported npm, pnpm, and Yarn dependency files and writes a shareable report of outdated direct dependencies and known advisories.

Public repositories only. The report checks dependency metadata, not application code or your database. It shows scan limits and does not change files or open a pull request.

Read next

npm audit fix is not working: why, and what to do instead · Upgrade React 18 to 19: a practical checklist