npm Global legacy-peer-deps Hides Conflicts - Fix Surprising Installs in CI
A globally configured legacy-peer-deps=true makes npm ignore peer-dependency conflicts everywhere on that machine. It hides ERESOLVE errors locally - so installs "work" for you but fail in CI (which lacks the global setting), or quietly produce a runtime-broken tree.
What this error means
Installs succeed on a developer machine but fail with ERESOLVE in CI, or vice versa. The difference is a legacy-peer-deps=true in a user/global .npmrc that suppresses peer conflicts on one side and not the other.
# locally (global legacy-peer-deps=true): install "passes"
$ npm ci
# in CI (no global setting): the real conflict surfaces
npm error code ERESOLVE
npm error unable to resolve dependency treeCommon causes
A global/user .npmrc sets legacy-peer-deps
npm config set legacy-peer-deps true writes to the user .npmrc, applying globally. It masks peer conflicts for every project, so the real mismatch is invisible until an environment without it installs.
CI and local diverge on the setting
CI typically does not inherit your user .npmrc, so a conflict you never see locally fails the pipeline - or the reverse, if CI sets it and local does not.
How to fix it
Resolve the conflict, not the symptom
Remove the blanket global flag and fix (or scope) the actual peer mismatch.
# inspect global config
npm config get legacy-peer-deps
npm config delete legacy-peer-deps # stop hiding conflicts globally
# then fix the real peer mismatch and regenerate the lockfile
rm -f package-lock.json && npm installMake config parity explicit
- Commit a project
.npmrcso every environment uses the same install behavior. - Avoid
npm config setfor project-affecting flags - it writes the user config. - Verify with
npm config ls -lthat CI and local agree.
How to prevent it
- Keep install-affecting config in a committed project
.npmrc. - Avoid global legacy-peer-deps; fix conflicts instead.
- Diff effective npm config between local and CI when installs disagree.