This error occurs when workspace packages have conflicting dependency versions. npm 7+ enforces peer dependency resolution strictly, causing failures when workspaces require different versions of the same package.
Fixes npm ERR! code ERESOLVE npm ERR! While resolving workspace dependencies
npm ERR! ERESOLVE could not resolve
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^18.0.0" from [email protected]npm ERR! ERESOLVE could not resolvenpm ERR! While resolving: [email protected]npm ERR! Found: [email protected]npm ERR! Could not resolve dependency:npm ERR! peer react@"^18.0.0" from [email protected]npm ERR! code ERESOLVEnpm ERR! While resolving workspace dependencies
The ERESOLVE error in workspaces means npm can't find a single version of a package that satisfies all workspace requirements. Since npm 7, peer dependencies are automatically installed and strictly validated. In a monorepo, if workspace-A needs `react@17` and workspace-B needs `react@18`, npm can't satisfy both because workspaces share a common node_modules at the root. This "hoisting" strategy requires version alignment. This is different from npm 6, which just warned about conflicts but continued installation.
Read the error output carefully—it shows exactly what conflicts:
npm ERR! ERESOLVE could not resolve
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^18.0.0" from [email protected]This tells you workspace-b needs react@18 but workspace-a has react@17.
The best fix is to use the same version everywhere. Update all workspace package.json files:
// packages/workspace-a/package.json
{
"dependencies": {
"react": "^18.0.0"
}
}
// packages/workspace-b/package.json
{
"dependencies": {
"react": "^18.0.0"
}
}Or define shared dependencies in the root package.json.
Force all packages to use a specific version using overrides in root package.json:
{
"overrides": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}Then reinstall:
rm -rf node_modules package-lock.json
npm installThis tells npm to use [email protected] regardless of what individual packages request.
Revert to npm 6's permissive behavior:
npm install --legacy-peer-depsTo make it permanent for the project, add to .npmrc:
legacy-peer-deps=trueWarning: This hides real conflicts that might cause runtime issues.
Force installation despite conflicts:
npm install --forceWarning: This can install incompatible versions and cause runtime errors. Only use when you understand the implications.
Move shared dependencies to the root package.json to ensure single versions:
// Root package.json
{
"dependencies": {
"react": "^18.2.0",
"lodash": "^4.17.21"
},
"workspaces": ["packages/*"]
}Workspaces automatically inherit root dependencies through hoisting.
Why npm 7+ is stricter: npm 6 treated peer dependencies as suggestions. npm 7+ automatically installs them and validates compatibility. This catches real bugs but breaks some legacy setups.
Hoisting in workspaces: npm workspaces hoist shared dependencies to the root node_modules. This is efficient but requires version alignment. If you need different versions, consider using separate non-workspace packages.
Override specificity: Overrides can be scoped:
{
"overrides": {
"workspace-a": {
"react": "^17.0.0"
},
"workspace-b": {
"react": "^18.0.0"
}
}
}This is complex and can lead to runtime issues—prefer aligning versions instead.
npm ci behavior: If package-lock.json was generated with --legacy-peer-deps, you must use that flag with npm ci too, or regenerate the lockfile.