# yarn-deduplicate fixes a lockfile problem that Yarn v1 creates and Yarn v2 solved natively

> A small TypeScript tool that rewrites yarn.lock so overlapping version ranges resolve to one installed copy, with strategies for choosing which version wins and a --fail flag for CI. The README is candid that it will change your dependency tree and that the default strategy can downgrade packages.

**scinos/yarn-deduplicate** — Deduplication tool for yarn.lock files

- Repository: https://github.com/scinos/yarn-deduplicate
- Stars: 1,392 · Forks: 57
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/scinos-yarn-deduplicate

## The tool exists because Yarn v1 stops deduplicating over time

yarn-deduplicate cleans up `yarn.lock` by removing duplicates, and the README opens with a scope limit that saves a lot of confusion. This package only works with Yarn v1, because Yarn v2 supports package deduplication natively.

The definition it works with is precise. A duplicate package is when two dependencies are resolved to a different version, even when a single version matches the range specified in the dependencies. More precisely, for this project a duplicated package is a package that appears on multiple nodes of the dependency tree with overlapping version ranges but resolved to different versions.

The example is the classic one. A project depends directly on `lodash@^1.0.0` and also depends on `babel`, which depends on `lodash@^1.1.0`. Because of how the resolution algorithm works in Yarn, you can end up with two different copies of lodash, for example 1.0.1 and 1.2.0, even though 1.2.0 would satisfy both requirements.

There is an important exclusion. Duplicated packages are not considered when the version ranges do not overlap, so a project depending on `underscore@^1.0.0` and `underscore@^2.0.0` keeps both versions and the tool will not change that. That is the right behaviour, since a major version bump genuinely can change behaviour.

The reason the tool is still needed, despite what Yarn's own documentation says, is explained with a scenario. The classic docs for the dedupe command say it isn't necessary because `yarn install` will already dedupe. The README says that is not exactly true, and gives the case. You install `libA`, which depends on `libB ^1.1.0`, and the latest `libB` at that moment is 1.1.2, so that is what lands in your repo. Days later you install `libC`, which also depends on `libB ^1.1.0`, but now the latest `libB` is 1.1.3. You end up with both 1.1.2 and 1.1.3. Nothing is wrong with either install; the duplication is a function of time.

## Two strategies, and one of them can downgrade your packages

The `--strategy <strategy>` option has two values, and the difference between them is the difference between a safe and an occasionally unwelcome outcome.

`highest` tries to use the highest installed version. With a lockfile like this, where `library@^1.1.0` resolves to 1.2.0, `library@^1.2.0` resolves to 1.2.0 and `library@^1.3.0` resolves to 1.3.0, it will deduplicate `library@^1.1.0` and `library@^1.2.0` to 1.3.0.

`fewer` tries to minimize the number of installed versions by deduplicating to the version that satisfies most of the ranges first. Given `library@*` at 2.0.0, `library@>=1.1.0` at 3.0.0 and `library@^1.2.0` at 1.2.0, it will deduplicate `library@*` and `library@>=1.1.0` to 1.2.0.

And here is the warning: this may cause some packages to be downgraded. The README says to be sure to check the changelogs between all versions and understand the consequences of that downgrade, and that if you are unsure, don't use this strategy.

That is the single most important sentence in the documentation for anyone running this on a production project. The `fewer` strategy optimises for the number of installed versions, and the version that satisfies the most ranges is not necessarily the newest or the safest. A patch release that fixed a crash might get replaced by an older version that has it.

There is a related warning about mixing. It is not recommended to use different strategies for different packages, and there is no guarantee the strategy will be honoured in subsequent runs of `yarn-deduplicate` unless the same set of flags is specified again.

That last point is subtle and important for automation. The tool does not record which strategy produced a given lockfile, so a later run with different flags can move things again in a direction you did not intend.

## The flags for going slowly, and the pre-release subtlety

The flags for incremental work are the ones to reach for on a real repository.

`--packages <package1> <package2> <packageN>` receives a list of packages to deduplicate and ignores any other duplicated package not in the list. The README recommends it when the number of duplicated packages in `yarn.lock` is too big to be easily reviewed by a human, and it allows a more controlled and progressive deduplication.

`--scopes <scope1> <scope2> <scopeN>` does the same at scope level, and is recommended when deduplicating a large number of interdependent packages from a single scope such as @babel, without specifying each package individually.

The excluding flags are `--exclude <package1> <package2> <packageN` and `--exclude-scopes <scope1> <scope2> <scopeN>`, and the README says these are specially useful if you want to apply a different strategy for a scope.

The pre-release behaviour is a detail that catches people. By default, yarn-deduplicate will only match pre-release versions if they share the same major, minor and patch versions, so `^1.2.3-alpha.1` and `1.2.3-alpha.2` can be deduplicated, but `^1.2.3` and `1.2.4-alpha.1` cannot. This matches the behaviour of semver. The `--includePrerelease` flag changes it so that all pre-release versions are treated as if they were normal versions, which means `^1.2.3` and `1.2.4-alpha.1` can be deduplicated.

That flag is worth understanding before you use it. Deduplicating a range to a pre-release version means shipping a pre-release to everyone who depends on that range, which is rarely what you want in a published package.

## The CI check is the feature most teams should want first

There is a usage in CI section and it is short, and it is arguably the most valuable thing in the tool.

The tool can be used as part of a CI workflow, and adding the flag `--fail` forces the process to exit with status 1 if there are duplicated packages.

```sh
# Print the list of duplicated packages and exit with status 1
yarn-deduplicate --list --fail
```

The combination of `--list` and `--fail` is the useful shape. It reports what is duplicated and fails the build, without changing the lockfile. That is a much safer way to introduce this tool than running the rewrite on the whole file, because the failure is a report you can act on rather than a diff you have to review.

The general usage is the same command on the lockfile.

```sh
yarn-deduplicate yarn.lock
```

If you do not specify the path it defaults to `yarn.lock`, and the default strategy is used to remove the duplicated packages. All available options are listed by `yarn-deduplicate --help`.

The README also states the caveat that belongs on every page of this tool's documentation: it will change your dependency tree, there are certain code paths that will now run with a different set of dependencies, and it is highly recommended that you review each change to `yarn.lock`. If the change is too big, use the `--packages` flag to deduplicate them gradually.

Installation is a global npm or yarn install, or no install at all with npx.

```sh
npm install -g yarn-deduplicate
```

```sh
npx yarn-deduplicate yarn.lock
```

The npx form is the one to reach for in a one-off situation, since it needs nothing on your machine.

## A small TypeScript tool with a narrow dependency set

The package metadata tells you the scope of the implementation, and it is appropriately small.

The runtime dependencies are three. `@yarnpkg/lockfile` at 1.1.0 or newer is the parser and serialiser for the lockfile format itself, `commander` at 10.0.1 or newer is the command line parser, `semver` at 7.5.0 or newer does the range matching that decides whether two ranges overlap, and `tslib` is the TypeScript runtime helper. The semver dependency is the one that matters, because the whole definition of a duplicate is expressed in terms of range overlap, and the pre-release rules follow semver's own behaviour by design.

The engines field says Node 14 or newer and yarn 1.x, so the tool is pinned to the same major version of the package manager it operates on. The main entry is `dist/index.js` with types at `dist/index.d.ts`, and the binary is `./dist/cli.js`.

The build is TypeScript with a project references build, `yarn clean && yarn tsc --build`, and the test script runs a build followed by jest. The `validate` script chains test, lint and typecheck, and lint is eslint, typecheck compiles both the source and the tests project.

The release process is automated with release-it, and the repository has a `renovate.json` for dependency updates, a `.eslintrc.js`, a `.prettierrc.js`, a `babel.config.js` and a `CHANGELOG.md` maintained with the keep-a-changelog package. There is a `CODE_OF_CONDUCT.md` and an `AUTHORS.md`.

The licence is Apache-2.0. The recent releases are v6.0.2 from 2023-05-11, v6.0.1 from 2022-12-11 and v6.0.0 from 2022-08-29, and the last push to the repository was on 2026-08-02 with the repository not archived.

That release history deserves one comment, because it is the most important fact for a prospective user. The versions have not moved since 2023, and that is consistent with the tool's purpose rather than a sign of neglect. The problem it solves is a Yarn v1 problem, and Yarn v1 is a thing teams are moving away from. The tool is finished work for a shrinking niche, which is the best situation it could be in.

## Conclusion

Adopt yarn-deduplicate if you are still on Yarn v1 and your lockfile has accumulated duplicate copies of the same package, because the tool does that narrowing deterministically and can fail a CI build when duplicates appear. Do not adopt it on Yarn v2 or later, because the README points out that Yarn v2 supports package deduplication natively. Verify first that the deduplicated version satisfies every range involved rather than assuming the newest one does, that no package gets silently downgraded under the fewer strategy, and that you review the lockfile diff rather than committing it unreviewed.

## FAQ

### What is a duplicated package in yarn.lock?

A package that appears on multiple nodes of the dependency tree with overlapping version ranges but resolved to different versions, even when a single version would satisfy both. Packages whose ranges do not overlap, such as underscore ^1.0.0 and ^2.0.0, are not considered duplicates and are left alone.

### What is the difference between the highest and fewer deduplication strategies?

Highest tries to use the highest installed version, while fewer tries to minimize the number of installed versions by deduplicating to the version satisfying the most ranges. The README warns that fewer may cause packages to be downgraded and says to check the changelogs, and that if unsure, do not use it.

### How do I use yarn-deduplicate in CI?

Add the --fail flag, which makes the process exit with status 1 if there are duplicated packages. The documented example is yarn-deduplicate --list --fail, which prints the list of duplicated packages and fails the build without changing the lockfile.

### Does yarn-deduplicate work with Yarn v2?

No. The README states that the package only works with Yarn v1, because Yarn v2 supports package deduplication natively. The package engines field also pins yarn to 1.x.

### How do I deduplicate a large number of packages gradually?

Use the --packages flag with a list of package names, or --scopes with a list of scopes such as @babel, and the tool will ignore any other duplicated package. The README recommends this when the number of duplicates is too big to review by a human.

## Sources

- [Issues](https://github.com/scinos/yarn-deduplicate/issues)
- [License: Apache-2.0](https://github.com/scinos/yarn-deduplicate/blob/master/LICENSE)
- [README](https://github.com/scinos/yarn-deduplicate/blob/master/README.md)
- [Releases](https://github.com/scinos/yarn-deduplicate/releases)
- [scinos/yarn-deduplicate on GitHub](https://github.com/scinos/yarn-deduplicate)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/scinos-yarn-deduplicate
