Run npm ls with the package name to print every installed copy and its place in the tree, then npm explain to see which dependency asked for it. Duplicates are common after a design system update, and they matter for bundle size, behavior and for knowing which version carries a vulnerability.
Why duplicates appear
Each package declares ranges for what it needs. If two packages ask for ranges that no single version satisfies, the installer keeps both. The npm dedupe documentation gives an example where one package needs a 1.0.x line and another needs a later minor, so the tree holds two copies at different depths.
After you update a shared component library, it may carry a different range than the apps around it. The result is a second copy of a utility, a date library, or occasionally a host library. For peer dependencies the aim is exactly one shared copy, which is the purpose of that field.
Step by step
- List copies. Run
npm ls PACKAGE --all. The command prints the versions installed and their dependents in a tree. It also reports extraneous, missing and invalid packages. - Ask why. Run
npm explain PACKAGE. It shows the chain from your root project to each copy and the range each parent requested. - Try to merge. Run
npm dedupe. It moves dependencies up the tree so compatible requests share one copy. There is also a find dupes command that reports without changing anything, covered in npm dedupe and find dupes. - Re-run the tests. Deduping can change which version a package receives. Run unit and visual tests before merging.
- Fix at the source if ranges disagree. Update the dependency that holds the old range, or widen the library's range, rather than forcing a version.
npm ls date-library --all
npm explain date-library
npm dedupe
The name above is a placeholder for whichever package you are checking.
Duplicates and security
Two copies means two versions to check. A scan that reports the patched version can still be wrong for your users if an older copy is also bundled. When you read a finding, look for every path, not just the first.
| Observation | What it suggests |
|---|---|
| Same package at two minors | Ranges that cannot merge; safe to try dedupe |
| Same package at two majors | A real compatibility split; plan an upgrade |
| Copy only under a dev tool | Probably not shipped, see do dev dependencies matter |
| Copy under the component library only | Library range should be raised or widened |
What to avoid
Do not respond with a blanket override as a first move. It can hide the mismatch and cause runtime errors if a package truly needs the older line. Read npm overrides: how to pin a transitive dependency before using one, and give any override an expiry.
Safeguard's dependency scanning lists every resolved version of a package per app, so you can see all the copies behind a single advisory. You can run a free scan at gold.safeguard.sh/scan.
Quick check
Is a duplicate always a problem?
No. Two copies at different majors can be correct. Treat it as a prompt to check why, not as an error.
Does npm dedupe change my lockfile?
Yes, it rewrites the tree and the lockfile, so review the diff and test before committing.
Sources
Last reviewed: 19 October 2026.