Yarn: [question] Why do `yarn upgrade [package]` and `yarn upgrade` choose different package versions?

Created on 29 Mar 2017  ·  8Comments  ·  Source: yarnpkg/yarn

https://yarnpkg.com/en/docs/cli/upgrade says for yarn upgrade that it

updates all dependencies to their latest version based on the version range specified in the package.json file

But it says for yarn upgrade [package] that it

upgrades a single named package to the version specified by the latest tag (potentially upgrading the package across major versions)

Why don't these commands behave equivalently as far as their strategy for choosing package versions? I would expect yarn upgrade [package] to do exactly what yarn upgrade does, just for a single package vs. all packages.

Put differently, why isn't there a command for upgrading just a single package to the latest version based on the range in package.json?

good first issue

Most helpful comment

In case it's useful to anyone finding/participating in this discussion, I've just found there's a currently undocumented upgrade-interactive command. Which is brilliant.

$ yarn upgrade-interactive
yarn upgrade-interactive v0.23.4
? Choose which packages to update. (Press <space> to select, <a> to toggle all, <i> to inverse selection)
 devDependencies
❯◯ postcss      5.2.17  ❯  6.0.1  http://postcss.org/
 ◯ postcss-cli  3.2.0   ❯  4.0.0  https://github.com/postcss/postcss-cli#readme
 ◯ sugarss      0.2.0   ❯  1.0.0  https://github.com/postcss/sugarss#readme

j and k navigate through the packages.

All 8 comments

This has been puzzling me too. Also I'd expect a command to be a bit more explicit if it's jumping major versions.

I don't know, I think it is a bug, feel free to send a PR to make them the same

I find having a command which upgrades a specific package to lateset quite useful. I hope this feature isn't removed.

It would _also_ be useful to be able to upgrade a specific package the the latest allowed by the packages.json specified version range.

In my opinion:

  • yarn upgrade should behave the same for a single package as well as all packages.
  • the default (and newly consistent) behavior should be to upgrade to the latest version based on the version range in the package.json file, since that's most conservative. It's also consistent with npm update.

@bhouser we could potentially add a flag to upgrade to make it upgrade to latest (potentially across major versions). However I don't think we need to do that because you can just rerun yarn add [package] and that will install latest.

Personally, I would expect yarn update [optional package] to update to the latest version matching the version range (also updating the lockfile if needed) while yarn upgrade [optional package] would go to the latest version, ignoring the version ranges. Keeps it nicely separated, too.

To add to @wearhere:
Whatever happens, the behaviour should indeed be the same, whether you're providing a specific package or not. However, with my proposed change above upgrade has one distinct advantage over re-running add: it can fail if you try to upgrade a package that is not a dependency of the project, whereas add would simply add it.

In case it's useful to anyone finding/participating in this discussion, I've just found there's a currently undocumented upgrade-interactive command. Which is brilliant.

$ yarn upgrade-interactive
yarn upgrade-interactive v0.23.4
? Choose which packages to update. (Press <space> to select, <a> to toggle all, <i> to inverse selection)
 devDependencies
❯◯ postcss      5.2.17  ❯  6.0.1  http://postcss.org/
 ◯ postcss-cli  3.2.0   ❯  4.0.0  https://github.com/postcss/postcss-cli#readme
 ◯ sugarss      0.2.0   ❯  1.0.0  https://github.com/postcss/sugarss#readme

j and k navigate through the packages.

While working on PR #3510 I discovered why this happens.

When you don't specify a package name, it loads the list of dependencies from your package.json file, including the version ranges.

When you specify a package name, it doesn't load package.json and instead uses what you passed in as the dependency list.

So upgrade is actually expecting something like: yarn upgrade foo@^1.2.3
But most people don't add that version range with the (false) assumption that Yarn will pick up the version range from package.json. It does not.

Under the covers the upgrade command actually passes the package list to the add command, and add does the actual work of resolving and installing the packages.

This means that yarn upgrade foo is roughly equivalent to yarn add foo which will go find the version tagged latest of foo (since no version range was specified) and install it.


I don't really like that behavior, but it made sense once I looked at the code.

I tried to start some discussion in #3384 about adding a flag to upgrade <package_name> that would tell it to use the version range in package.json, but didn't see much feedback, so haven't put together a PR for that yet.

I'm going to mark this issue closed because the original question (why does it behave like this) is answered.

I'd like to move the discussion about making a breaking change to redefine how upgrade and upgrade-interactive determine version ranges to #3603

Was this page helpful?
0 / 5 - 0 ratings