131

If my package has these dependencies

{ "name": "my-package",
  "dependencies": { "foobar":"~1.0.3", "baz":"2.0.9" }

And the foobar package has these dependencies

{ "name": "foobar",
  "dependencies": { "baz":"^2.0.0" }

and the most recently released version of baz is 2.1.0, the first run of yarn will install baz@2.1.0 in foobar/node_modules.

How do I force yarn to use the baz@2.0.9 package for foobar?

My understanding is that this would be possible using npm shrinkwrap (a la this question).


The summary of my question probably is: Yarn creates repeatable, deterministic installations, but how do I customize that installation?

Community
  • 1
  • 1
Chris W.
  • 37,583
  • 36
  • 99
  • 136
  • 1
    Did you guys ever find an answer to this? – atomman Oct 29 '16 at 16:52
  • @atomman actually I think I was wrong in the basis for this question. Yarn had determined that there was an incompatibility between my top level package version number and another dependency's sub-dependency. So it correctly decided give the dependency its own version of that library. – Chris W. Nov 07 '16 at 18:21
  • 1
    Thanks for answering. Although I'm not sure I agree, as baz@2.0.9 would satisfy all requirement. Though it could be seen as a feature that yarn always provides the most up-to-date dependency for sub-modules. I do however feel like yarn should provide a dependency-resolution mechanism for these cases, but thats another discussion. :) – atomman Nov 08 '16 at 11:56
  • @atomman oh, yes, i agree with you (and with the premise in my question) however I think the real problem I was *actually* having was subtly different from the one i described in my question. – Chris W. Nov 08 '16 at 17:41

3 Answers3

177

If you do in fact have a sub-dependency that is overly restrictive in what versions it will accept, you can override them using yarn.

UPDATED EDIT: Yarn now, as of 1.0, officially supports the "resolutions" block. So the way to override resolutions is to just add a block like this to package.json:

"resolutions": {
      "package-a": "2.0.0",
      "package-b": "5.0.0",
      "package-c": "1.5.2"
}

You'll get warnings for "incompatible" versions sometimes, but I find that some packages (like socket.io) are overly restrictive in what version they accept, and so I'll happily select the latest version when it doesn't actually break things.

Original but outdated answer below.

It sounds like the original question wasn't exactly correct, but the original question was in fact the one I wanted answered, and I found an answer, so here it is for posterity:

I'm using the socket.io library, and it has component-emitter as a dependency. But it has a pair of versions that it requires. This is what the yarn.lock file looked like before I changed anything:

component-emitter@1.1.2:
  version "1.1.2"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"

component-emitter@1.2.0:
  version "1.2.0"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.0.tgz#ccd113a86388d06482d03de3fc7df98526ba8efe"

So it was including two copies of the component emitter in my client code. I looked, and there didn't appear to be any breaking changes between 1.1.2 and 1.2.0 (or 1.2.1, which was current). I first tried just changing the yarn.lock file:

component-emitter@1.2.1, component-emitter@^1.2.1, component-emitter@1.1.2:
  version "1.2.1"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"

This worked, but the file has warnings about it being autogenerated, meaning that every single update or new package I add will stomp on this change. A bit of searching found the yarn --flat option, which will force yarn to choose no more than one of each package in the entire project. That seems like overkill to me, since I'm sure there are actual cases of incompatibility between older and newer packages. I just wanted to eliminate a redundant package from my client code, to make the download smaller; I still want the development packages to all work correctly.

But in the docs to yarn --flat I found a reference to a "resolutions" block that can go in package.json:

"resolutions": {
  "package-a": "2.0.0",
  "package-b": "5.0.0",
  "package-c": "1.5.2"
}

So I tried putting "component-emitter" : "1.2.1" in a new "resolutions" block in my package.json, and it in fact flattened component-emitter to 1.2.1 for all places that required it, and now I have only one copy in my client code.

(And now the resolutions block is completely supported in yarn, so you don't even need to use --flat.)

SomeCallMeTim
  • 4,503
  • 2
  • 28
  • 27
  • 3
    Thanks a lot for this answer. So i guess the solution is at least in part is "edit the yarn.lock file", which is what i was afraid of doing in the first place. But it makes sense that yarn wont go out of its way to nuke that file. – Chris W. Dec 15 '16 at 04:18
  • Worked for me without touching `package.json`. Had `async-busboy` dep and wanted to change the version of its sub-dep - `busboy`. So I just replaced `busboy "0.2.13"` with `busboy "mscdex/busboy#76c3d58"`, ran `yarn install`, and voila, everything works. Strangely, yarn didn't update the "busboy" block in the lock file, but that doesn't bother me too much, as long as it works. – Alec Mev Jan 18 '17 at 15:02
  • Sure, as long as you use only yarn ever. If someone else comes along and runs `npm install`, though, they'll get the wrong version. I *think* that if you modify both it might still work, though not as fine-grained as with yarn -- and if what you're installing is a dependency of another package that you add, the "resolutions" should at least override the new package dependencies so that you don't end up with many versions of the same package. – SomeCallMeTim Jan 19 '17 at 22:26
  • 1
    This does **not** work in a robust long term way. As soon as `yarn upgrade` is run, the `yarn.lock` file is overwritten, and the `resolutions` section in your `package.json` is ignored by nested dependencies. – Michael Plotke May 03 '17 at 14:34
  • @MichaelPlotke Reproduced. Sure enough. So beware global `yarn upgrade` calls. I've only upgraded packages individually, but I can understand why you'd want to just "upgrade everything." But yes, you'll have to check anything you've explicitly overriden if you do that. – SomeCallMeTim May 04 '17 at 19:59
  • 1
    @MichaelPlotke And now Yarn 1.0 officially supports the "resolutions" section, so my answer works again. :) – SomeCallMeTim Sep 07 '17 at 16:17
  • 1
    Unfortunately, this doesn't seem to work with renamed packages. For example, `babel-core` which was renamed to `@babel/core` in its newer version is impossible to override using resolutions afaik. – Evgeny Apr 08 '18 at 07:19
  • For renamed packages, I'd put in a feature request (or star one if it exists already) for yarn. I'd actually use that functionality myself, since there are times that I want my OWN fork of a package to be used as a dependency. – SomeCallMeTim Apr 09 '18 at 15:45
  • Unfortunately, this does not work when using yarn workspaces. It is such a PITA if one is using TypeScript typings from @types/ namespace. It is common to declare their dependencies with asterisk "*"! – Marecky Feb 27 '19 at 11:03
  • My project uses create-react-app and has redux installed. Redux package has a fixed dependency on immer@8.0.1 which is being flagged with a vulnerability with blackduck scanner. I tried using resolutions to force it to 9.0.6, but it doesn't seem to be working. Any ideas on how to resolve this? – Alex Sep 29 '21 at 19:52
  • 1
    I tried everything on the internet for the issue I'm facing while deploying my Nodejs Application in Jenkins throwing vulnerabilities in SEC:CSS (Prisma). To update the peer dependencies this is the best way to achieve it. – Bunny Joel Apr 29 '22 at 00:27
78

This is now possible with yarn's selective version resolution feature.

In your project's main (root) package.json, use resolutions:

  "resolutions": {
    "foobar/**/baz": "2.0.9"
  }

This overrides package foobar's (and any other packages under it) version of baz, forcing it to be version 2.0.9.

jorisw
  • 875
  • 1
  • 11
  • 17
Tom Hale
  • 40,825
  • 36
  • 187
  • 242
  • 2
    Does not work with workspaces :( See my comment above. – Marecky Feb 27 '19 at 11:03
  • 11
    @Marecky it does work with workspaces, but you have to put the resolutions in the top level package.json – steezeburger Feb 09 '21 at 22:27
  • 2
    Problem for me is the dependent deprecated package in use has been renamed/replaced with something entirely different. So `parent` lists `libA` as dependent. But `libA` is deprecated and renamed to `libB`. How do I tell `parent` to use `libB`? – Mike S. Mar 07 '22 at 23:52
  • @steezeburger it took me weeks to find your comment to solved a problem that took me days :D are you still active and willing to post this as an answer? I know this whole thing is years old, but still a badly documented issue. – Basti Jun 13 '23 at 15:37
  • It does not work in Yarn 3. Using `**` results in the following error when running `yarn`: `Expected "@", [^/@], or end of input but "/" found` – Mateus Ferreira Jun 15 '23 at 00:20
2

EDIT: This is now deprecated, please read this answer instead:

https://stackoverflow.com/a/46615878/2398593


@SomeCallMeTime's answer is great and we've been doing that for month at work.

Unfortunately, this is not possible anymore since the v0.24.x (see that comment).

There's an opened PR on Github with an RFC proposal to have a simple way of handling that use case without having to keep an eye on the generated lockfile.

maxime1992
  • 22,502
  • 10
  • 80
  • 121