22 min read
What Causes npm Dependency Conflicts?
An npm dependency conflict occurs when two or more packages in a JavaScript project require incompatible versions of the same dependency, or when a package’s peer dependency requirements cannot be satisfied by the versions installed in the project. These conflicts can prevent developers from installing packages, updating libraries, building applications, or deploying code successfully. One of the most common errors is npm ERESOLVE unable to resolve dependency tree, which indicates that npm cannot construct a dependency tree that satisfies all required version constraints.
Understanding why npm dependency conflicts occur is essential for maintaining reliable Node.js applications, React projects, Angular applications, Vue.js websites, and other JavaScript-based systems. Conflicts can result from incompatible package versions, outdated dependencies, incorrect version ranges, peer dependency requirements, or differences between local development environments and continuous integration pipelines.
This guide explains the causes of npm dependency conflicts, how npm resolves dependencies, how to identify incompatible packages, and how to fix common errors without unnecessarily breaking your project.
What Is an npm Dependency Conflict?
An npm dependency conflict happens when the dependencies declared by different packages cannot be satisfied simultaneously under npm’s dependency resolution rules. Every JavaScript package can depend on other packages, creating a dependency tree that npm must resolve during installation.
For example, suppose your project uses React 18, but a UI component library requires React 17 as a peer dependency. If the library does not support React 18, npm may report a conflicting peer dependency error.
Consider this simplified example:
{
"dependencies": {
"react": "^18.0.0",
"example-ui-library": "^2.0.0"
}
}If example-ui-library declares a peer dependency that only supports React 17, the versions may be incompatible. npm must determine whether a valid dependency tree exists. If it cannot satisfy the requirements, installation may fail.
What Is the npm Dependency Tree?
The npm dependency tree represents the packages installed in a project and their relationships. A package may depend directly on another package, which may itself require additional dependencies.
For example:
- Your application depends on React.
- A UI library depends on React as a peer dependency.
- A development tool depends on a particular TypeScript version.
- A build tool depends on another package with its own version requirements.
These relationships create a dependency tree. Dependency tree resolution becomes difficult when package requirements overlap but cannot be satisfied by a compatible set of versions.
A dependency tree may contain hundreds or thousands of packages, especially in modern frontend applications. Consequently, a conflict can originate from a package that you never installed directly.
What Causes npm Dependency Conflicts?
Several factors can cause an npm dependency conflict. Identifying the actual cause before applying a fix is more reliable than repeatedly reinstalling packages.
1. Incompatible Package Versions
An npm package version incompatibility occurs when a package requires a version of another library that conflicts with the version available in your project.
Suppose your application uses a library that supports React 18, while another library only supports React 17. Installing both packages may create incompatible package versions.
Common causes include:
- Upgrading a major framework version without checking compatibility.
- Installing an outdated plugin.
- Combining libraries designed for different framework releases.
- Using a package version that no longer supports your Node.js version.
- Updating one dependency while leaving related packages unchanged.
The correct solution is to identify the supported versions and select compatible packages.
2. npm Peer Dependency Conflict
An npm peer dependency conflict occurs when a package expects the consuming application to provide a compatible version of another package.
Peer dependencies are common in plugins, UI component libraries, testing tools, and framework extensions.
PeerDependencies vs Dependencies
| Feature | dependencies | peerDependencies |
|---|---|---|
| Purpose | Packages needed by a library | Packages expected from the consuming project |
| Installation | Installed as part of dependency resolution | npm resolves compatibility requirements with the project |
| Common examples | Utility libraries, runtime packages | React, ESLint plugins, framework integrations |
| Conflict risk | Version requirements can overlap | Incompatible host-package versions can prevent installation |
For example, a React component library may declare:
{
"peerDependencies": {
"react": "^17.0.0"
}
}If your project uses React 18, the library’s declared requirements may conflict with your installed version.
A conflicting peer dependency message indicates that npm has identified incompatible requirements involving a peer dependency. However, the message alone does not always prove that the package is fundamentally incompatible; inspect the exact versions and the package’s compatibility documentation.
3. Incorrect Version Ranges
Package versions in package.json often use semantic versioning and version ranges.
Semantic versioning generally represents versions as MAJOR.MINOR.PATCH. A major version change can introduce breaking changes, while minor and patch releases are generally intended to preserve backward compatibility within the same major version.
Common version range symbols include:
^: Allows compatible updates below the next major version for versions at or above 1.0.0.~: Generally allows patch updates within the specified minor version.- An exact version, such as
2.4.1: Requests that particular release.
For example:
{
"dependencies": {
"example-package": "^2.4.0",
"another-package": "~1.6.2"
}
}The first range generally permits compatible updates below version 3.0.0. The second generally permits patch updates within version 1.6.x.
Problems arise when a package’s declared version range does not overlap with the versions required by another dependency. This is one reason why understanding caret and tilde version constraints helps prevent installation errors.
4. Transitive Dependencies
Transitive dependencies are packages required by your direct dependencies rather than explicitly installed by your application.
For example:
- Your project installs a frontend framework.
- The framework requires a build utility.
- The build utility requires another package.
- Another direct dependency requires an incompatible version of that same package.
This creates a conflict involving direct vs indirect dependencies.
Direct dependencies appear in your project’s dependency declarations. Indirect dependencies are introduced through other packages.
A transitive dependency conflict can be difficult to diagnose because the package causing the problem may not appear directly in your package.json.
5. Outdated Packages and Breaking Changes
Outdated packages can introduce compatibility problems when developers install newer frameworks or tools without updating their plugins.
For example, an older ESLint plugin may not support the installed ESLint version. Similarly, an older build tool may rely on APIs removed from a newer release of another package.
Use the following command to inspect outdated packages:
npm outdatedThe output helps you identify packages with newer available releases. However, upgrading everything at once is not always the best solution. Review release notes and compatibility requirements before performing dependency upgrades and downgrades.
6. Node.js and npm Version Compatibility
Some packages require specific Node.js versions or npm capabilities. Using an unsupported Node.js version may produce installation failures or runtime errors.
Check your installed versions:
node -v
npm -vCompare these results with the package’s documented engine requirements. Also check the project’s .nvmrc, package.json engines field, and CI configuration when available.
Maintaining consistent Node.js and npm versions across development and deployment environments reduces unexpected dependency resolution differences.
7. Incorrect or Stale Lockfiles
The package-lock.json file records the resolved dependency tree so that installations can be reproduced across environments.
Package-lock.json conflicts may occur after manual edits, incomplete merges, dependency changes, or inconsistent package manager usage.
A stale lockfile is not automatically incorrect. In many cases, it preserves a valid and reproducible dependency tree. Avoid deleting it simply because npm reports an error.
Instead, inspect the error, determine whether the lockfile is inconsistent with package.json, and regenerate it only when necessary.
8. Conflicts in Development Dependencies
The devDependencies section contains packages used during development, testing, linting, and building.
Common examples include:
- TypeScript
- ESLint
- Vite
- Webpack
- Testing libraries
- Build plugins
A TypeScript version conflict can occur when a framework plugin supports a different TypeScript range than the installed compiler. An ESLint dependency conflict can happen when an ESLint plugin requires a newer or older version of ESLint.
Development dependencies can therefore prevent installation even when the application’s runtime dependencies appear compatible.
9. Optional Dependencies and Platform Differences
Optional dependencies are packages that may be installed when available but are not always essential to a package’s operation. Some are platform-specific, such as packages that provide native binaries.
Operating system differences, processor architecture, optional package installation, and environment configuration can cause installations to behave differently on Windows, Linux, macOS, or CI servers.
These issues are not necessarily peer dependency conflicts, but they can produce npm installation errors that require separate investigation.
Common npm Dependency Conflict Errors
npm ERESOLVE Unable to Resolve Dependency Tree
The npm ERESOLVE unable to resolve dependency tree error is one of the most recognizable npm dependency resolution errors.
It commonly appears when npm cannot find a dependency arrangement that satisfies the declared package requirements.
A terminal message may look like this:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! While resolving: my-project@1.0.0
npm ERR! Found: react@18.2.0
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.0" from example-ui-library@2.0.0This example indicates that the project uses React 18.2.0, while the example library declares a React 17 peer dependency requirement.
The correct fix is to verify whether a newer library release supports React 18, use a compatible version of the library, or choose a framework version supported by all required packages.
npm ERR! ERESOLVE
The npm ERR! ERESOLVE message identifies a dependency resolution failure. The most useful diagnostic details usually appear immediately before and after the error.
Look for:
- The package npm is resolving.
- The version it found.
- The version range another package requires.
- The package responsible for the peer dependency requirement.
- Any suggested alternative versions.
These details help you identify the incompatible packages instead of applying a workaround blindly.
Framework-Specific Dependency Conflicts
Different frameworks have their own common conflict patterns.
React Dependency Conflict
React dependency conflicts frequently involve React, React DOM, component libraries, testing utilities, and framework integrations.
React and React DOM Version Mismatch
React and React DOM should generally use compatible versions. A mismatch can cause installation issues or unexpected runtime behavior.
React Peer Dependency Error
A React peer dependency error often means a plugin or component library does not declare support for the installed React version.
Angular npm Dependency Conflict
An Angular npm dependency conflict can occur when Angular framework packages, Angular CLI, TypeScript, or third-party libraries require incompatible versions.
Vue.js Dependency Conflict
A Vue.js dependency conflict may involve Vue 2 versus Vue 3, incompatible component libraries, or plugins designed for different Vue releases.
TypeScript Version Conflict
TypeScript conflicts often involve frameworks, build tools, type definitions, or plugins with specific compiler requirements.
ESLint Dependency Conflict
ESLint dependency conflicts commonly involve ESLint major versions and plugins or configurations that have not yet adopted the same version.
Vite Dependency Conflict
A Vite dependency conflict can arise when a Vite plugin requires an incompatible Vite version or another build dependency.
Webpack Dependency Conflict
Webpack conflicts can involve loaders, plugins, Webpack major versions, and Node.js compatibility.
Next.js npm Dependency Conflict
A Next.js npm dependency conflict may involve Next.js, React, React DOM, TypeScript, ESLint, or an incompatible third-party integration.
The general principle is the same: verify the compatibility requirements of the exact package versions before changing your dependency tree.
How to Fix npm Dependency Conflicts
The most reliable npm package manager troubleshooting process starts with diagnosis and then applies the smallest necessary change.
Step 1: Read the Complete Error Message
When npm install fails, read the complete terminal output.
Look for the Found, Could not resolve dependency, and peer lines. These often identify the incompatible versions and the package responsible.
Do not assume that the last package mentioned in the output is always the root cause. Trace the requirements to understand which version constraints are incompatible.
Step 2: Inspect the Dependency Tree
Use these commands to investigate installed packages:
npm ls
npm ls react
npm explain reactnpm lsdisplays the installed dependency tree.npm ls reactfocuses on React dependencies.npm explain reactexplains why React is present in the dependency tree and which packages require it.
These commands help with how to identify incompatible npm packages and trace indirect dependencies.
Step 3: Check Package Compatibility
Inspect the package’s peer dependencies:
npm view example-ui-library peerDependenciesReplace example-ui-library with the actual package name.
You can also check a specific version:
npm view example-ui-library@2.0.0 peerDependenciesThis reveals the package’s declared peer dependency requirements and helps you determine whether your installed framework version is supported.
Step 4: Choose Compatible Package Versions
Use the following command to install a particular version:
npm install example-ui-library@2.1.0Choose a version only after verifying its compatibility with your framework and other dependencies.
If an older package does not support your current framework, consider upgrading that package, replacing it with a maintained alternative, or using a compatible framework release.
This is generally safer than forcing npm to accept incompatible requirements.
Step 5: Update Dependencies Carefully
The npm update command updates packages within the version ranges permitted by your project configuration.
npm updateReview the changes and run your tests afterward. Remember that npm update does not necessarily move every package to its newest major release.
For larger upgrades, update related packages together and consult their release notes.
Step 6: Run npm Dedupe
The npm dedupe command attempts to simplify the dependency tree by moving compatible packages higher in the tree and reducing unnecessary duplication.
npm dedupeThis may help when multiple compatible versions of the same package are installed in different locations. However, it cannot resolve fundamentally incompatible version requirements.
Step 7: Reinstall Dependencies When Necessary
If the dependency tree or installation state appears inconsistent, a clean installation can help.
First, preserve your existing lockfile and commit or back up important changes.
Then remove installed packages:
npm uninstall example-package
npm installThe npm uninstall and reinstall dependencies approach is useful when you need to replace a problematic package or refresh the installation.
For a more complete clean installation, remove node_modules and reinstall from the existing lockfile:
npm ciThe npm ci command performs a clean installation using package-lock.json. It fails if the lockfile and package.json are inconsistent, rather than silently rewriting the lockfile.
When Should You Delete node_modules and package-lock.json?
Deleting node_modules is often reasonable when you suspect a corrupted or inconsistent local installation.
Deleting package-lock.json is a different decision. It can change many resolved dependency versions and make future installations less reproducible.
If the lockfile itself must be regenerated, preserve a backup first and use:
npm installThis allows npm to generate a new lockfile based on the declared dependencies and the available package versions.
Do not delete the lockfile as your first response to every npm ERESOLVE error.
Step 8: Clear the npm Cache Only When Appropriate
The npm cache can occasionally contribute to download or integrity problems, but clearing it usually does not fix genuine peer dependency incompatibilities.
You can verify the cache with:
npm cache verifyIf you have evidence of a cache-related issue, npm cache clean --force is available, but it should not be a routine dependency conflict fix.
Step 9: Review Security Updates
The npm audit fix command attempts to apply compatible dependency updates that address known security vulnerabilities.
npm audit fixUse it when security findings justify the update. It is not a universal solution for dependency conflicts, and you should review the resulting changes and test the application.
Avoid treating security updates and dependency compatibility fixes as interchangeable problems.
When to Use --legacy-peer-deps vs --force
Two frequently suggested workarounds are npm install --legacy-peer-deps and npm install --force. They behave differently and should not be used without understanding the implications.
Using npm install –legacy-peer-deps
npm install --legacy-peer-depsThis tells npm to ignore peer dependency requirements when constructing the dependency tree, broadly following the behavior used by older npm versions.
It can help when installing an older package whose peer dependency declarations prevent installation even though the combination has been tested and is known to work.
However, it does not make incompatible packages compatible. Runtime errors, build failures, or unexpected behavior may still occur.
Using npm install –force
npm install --forceThis disables certain npm protections and permits operations that npm would otherwise reject. It is broader than simply ignoring peer dependencies and can allow a potentially incompatible dependency tree.
Use it cautiously and only when you understand the specific risk.
Should You Set legacy-peer-deps Globally?
You may encounter this command:
npm config set legacy-peer-deps trueIt configures npm to use legacy peer dependency handling by default for the applicable configuration scope.
A project-specific workaround may be preferable to a global setting because global configuration can affect unrelated projects.
If your team must use this option for a known compatibility reason, document why it is necessary and ensure that your development and CI environments use consistent settings.
Best practice: Prefer resolving the actual package incompatibility. Use --legacy-peer-deps or --force only when you have a clear reason and have tested the result.
How to Fix ERESOLVE Without Force
If you want to know how to fix ERESOLVE without force, follow this sequence:
- Read the complete error output.
- Identify the package and version causing the conflict.
- Check the package’s
peerDependencies. - Inspect the installed tree with
npm lsandnpm explain. - Select compatible package versions.
- Update or replace the incompatible dependency.
- Reinstall using the appropriate installation command.
- Run tests, builds, and application checks.
This method addresses the underlying issue rather than suppressing npm’s compatibility checks.
Advanced Dependency Conflict Management
npm Overrides
The overrides field in package.json lets you specify alternative dependency versions for packages in your dependency tree.
For example:
{
"overrides": {
"example-utility": "2.4.1"
}
}Overrides can be useful when a transitive dependency needs a compatible update or a specific release addresses a known issue.
However, forcing a package version through overrides may break a parent package that expects a different API. Confirm compatibility and test the result before adopting an override.
npm Workspaces Dependency Conflicts
npm workspaces allow multiple packages to be managed in a single repository. Conflicts may occur when workspace packages require incompatible versions of shared libraries or when the root project has inconsistent dependency declarations.
To troubleshoot npm workspaces dependency conflicts:
- Inspect the root and workspace
package.jsonfiles. - Check shared package version requirements.
- Avoid unnecessary duplication of framework dependencies.
- Verify workspace-specific peer dependencies.
- Run installation and tests from the repository root.
A monorepo should define a clear dependency strategy so that workspace packages can be developed and installed consistently.
npm vs Yarn vs pnpm Dependency Resolution
npm, Yarn, and pnpm all manage JavaScript dependencies, but they differ in installation strategies, lockfile formats, workspace features, and dependency isolation.
| Package manager | Lockfile | Important consideration |
|---|---|---|
| npm | package-lock.json | Native integration with Node.js and npm workflows |
| Yarn | yarn.lock | Behavior varies by Yarn version and configuration |
| pnpm | pnpm-lock.yaml | Uses a content-addressable store and a distinctive dependency layout |
Switching package managers does not automatically resolve incompatible peer dependency requirements. Each tool may report or handle certain situations differently, but an unsupported package combination remains a compatibility concern.
Choose one package manager for a project and commit its corresponding lockfile to support reproducible npm installs or their equivalents in other package managers.
How to Prevent Recurring npm Dependency Conflicts
Preventing conflicts is more efficient than repeatedly fixing broken installations.
Follow Dependency Management Best Practices
Adopt these practices:
- Commit
package-lock.jsonto version control. - Use consistent Node.js and npm versions across environments.
- Review package compatibility before major upgrades.
- Avoid unnecessary changes to dependency versions.
- Pin versions when reproducibility or compatibility requires it.
- Keep framework-related packages on compatible release lines.
- Test dependency updates before merging them.
- Document any required npm configuration workarounds.
- Review third-party package maintenance and security status.
- Avoid blindly running commands that rewrite the dependency tree.
These best practices for dependency management improve long-term project stability.
Maintain a Dependency Compatibility Matrix
A dependency compatibility matrix records which versions of your framework, runtime, compiler, plugins, and related packages work together.
For example, a project might document:
- Supported Node.js versions.
- Compatible React and React DOM versions.
- Supported TypeScript releases.
- Compatible ESLint and plugin versions.
- Approved build tool versions.
- Required npm installation settings.
This matrix makes dependency upgrades easier to review and helps developers identify conflicts before they reach production.
Ensure Reproducible Builds
Reproducible npm installs help developers and CI systems use the same resolved dependency tree.
For projects with a committed, valid lockfile, use:
npm ciThis is particularly useful for automated builds because it installs the locked dependency versions rather than resolving a fresh set of versions.
It also helps expose lockfile inconsistencies early in the development process.
npm Dependency Conflicts in CI/CD and GitHub Actions
An npm dependency conflict in CI/CD can appear even when installation succeeds locally. Common reasons include different Node.js versions, different npm versions, missing lockfiles, inconsistent configuration, or environment-specific optional dependencies.
For npm dependency conflict in GitHub Actions, use a consistent Node.js setup and install from the lockfile.
For example:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm test
- run: npm run buildThe Node.js version shown is an example; select a version supported by your project and its dependencies.
If local installation succeeds but CI fails, compare the runtime versions, lockfile, npm configuration, and environment-specific packages. Avoid immediately adding --force to the pipeline, as this may conceal a compatibility problem.
Step-by-Step npm ERESOLVE Troubleshooting Example
Consider a project that reports a React peer dependency error after installing a component library.
Scenario
Your project contains:
{
"dependencies": {
"react": "^18.2.0",
"example-ui-library": "^2.0.0"
}
}The installation output says the library requires React 17.
Solution
Step 1: Inspect the library requirements.
npm view example-ui-library@2.0.0 peerDependenciesStep 2: Check whether a newer library version supports React 18.
npm view example-ui-library versions
npm view example-ui-library@latest peerDependenciesStep 3: Install a compatible release.
If the latest release supports your React version, install the verified compatible version:
npm install example-ui-library@latestAlternatively, select a specific supported release instead of using latest.
Step 4: Verify the resulting tree.
npm ls react react-dom example-ui-libraryStep 5: Test the application.
npm test
npm run buildIf no compatible release exists, consider replacing the library or using a supported React version. This example demonstrates how to resolve a dependency conflict without unnecessarily forcing npm to accept incompatible packages.
How to Identify Incompatible npm Packages Efficiently
When npm install is not working, use a focused diagnostic checklist.
- Check the error: Find the exact package and version mentioned in the ERESOLVE output.
- Inspect the tree: Run
npm lsandnpm explain package-name. - Check package metadata: Use
npm view package-name peerDependencies. - Review version ranges: Compare
package.jsonrequirements with the package’s compatibility documentation. - Inspect the lockfile: Determine whether the locked versions match the intended dependency configuration.
- Check runtime versions: Verify Node.js and npm compatibility.
- Change one dependency at a time: Avoid introducing several unknown variables.
- Validate the result: Run tests, linting, builds, and application checks.
This npm troubleshooting guide helps distinguish package incompatibility from corrupted installations, security problems, and environment-specific failures.
For a broader development workflow, read our guide on what is debugging, which explains the process of identifying, isolating, and fixing software problems.
Frequently Asked Questions
What Causes an npm Dependency Conflict?+
An npm dependency conflict usually occurs when packages require incompatible versions of another dependency, peer dependency requirements cannot be satisfied, or package versions are incompatible with the framework or runtime. Outdated plugins, incorrect version ranges, transitive dependencies, and inconsistent lockfiles can also contribute.
How Do I Fix ERESOLVE Unable to Resolve Dependency Tree?+
Read the complete error message, identify the conflicting packages, inspect peer dependency requirements, and install compatible versions. Commands such as npm ls, npm explain, and npm view package-name peerDependencies can help identify the cause.
Is --legacy-peer-deps Safe?+
It can be useful as a temporary workaround for a known compatibility issue, but it ignores peer dependency requirements during resolution. Packages may still be incompatible at runtime. Test the application and document the reason for using the option.
Should I Use --force or --legacy-peer-deps?+
Neither should be the default solution. --legacy-peer-deps ignores peer dependency requirements, whereas --force disables certain npm protections more broadly. Prefer installing compatible package versions and use either workaround only when the risks are understood.
Can Deleting package-lock.json Fix npm Conflicts?+
Sometimes regenerating the lockfile resolves an inconsistent dependency configuration, but deleting it can also change many dependency versions and reduce reproducibility. First inspect the error and preserve the existing lockfile. Use npm ci when you want a clean installation from a valid lockfile.
How Do I Find Which Package Causes a Dependency Conflict?+
Start with the complete ERESOLVE error. Then run npm ls package-name, npm explain package-name, and npm view package-name peerDependencies using the relevant package names. Review the dependency tree to identify which package requires the incompatible version.
How Can I Resolve npm Dependency Conflicts Without Breaking My Project?+
Back up or commit your current changes, inspect package requirements, update only the necessary dependencies, and test the application after each change. Keep the lockfile consistent, use npm ci for reproducible installations, and avoid forcing incompatible dependency trees without verification.
What Is the Difference Between a Dependency Conflict and a Security Vulnerability?+
A dependency conflict is a compatibility or version resolution problem. A security vulnerability is a weakness that could affect the confidentiality, integrity, or availability of a system. They may overlap when an incompatible update is also needed to fix a vulnerability, but the problems require different diagnostic approaches.
Conclusion
An npm dependency conflict is usually caused by incompatible package versions, conflicting peer dependencies, incorrect version ranges, transitive dependency requirements, outdated development tools, or inconsistent environments. The npm ERESOLVE unable to resolve dependency tree error is a signal to investigate these requirements rather than automatically force installation.
Start by examining the error output, checking package metadata, and tracing the dependency tree. Choose compatible versions, update dependencies carefully, and preserve your lockfile whenever possible. Use npm dedupe, npm ci, or lockfile regeneration when appropriate, and reserve --legacy-peer-deps and --force for situations where you understand the consequences.
By following a structured troubleshooting process and maintaining consistent development environments, you can resolve npm dependency conflicts more safely, reduce recurring installation errors, and keep your JavaScript projects stable and maintainable.
