Why Running yarn upgrade
Does Not Update My package.json
Today I wanted to upgrade the dependency of React of one of my projects. So I ran
yarn upgrade react
And it seems everyone was happy.
Then I checked my package.json
, nothing changed.
"react" "^16.5.1",
"react-dom": "^16.5.1",
My first Google enquiry was yarn upgrade does not update package.json. A few results seemed to be indicating bug in earlier versions of Yarn. But it didn't seem to be going anywhere.
Yarn's official doc clearly indicated that running such command should update the dependency here.
I then checked my yarn.lock
and realized that the latest versions of my upgrading packages are already installed.
Why, why, why 🤷🏻♀️
I had a rough understanding of what might have happened here. The current react@^16.5.1
accepts the upgraded version 16.8.6
, as indicated by yarn.lock
.
But what is a proper way for me to upgrade dependency in this semantic situation? Namely, to upgrade dependency to latest package and indicating that my app now depends on that version?
I mean, other than manually changing package.json
?
I played around a few things to do. Some apparently not the right direction, but they helped to gain some understanding of the situation.
Understanding the semantic versioning ranges
The installed version in our node_modules
might not be the literal number we see in our package.json
. This is because the versions we indicate can be a range.
For example, the caret ranges are specified as follows:
Allow changes that do not modify the first non-zero digit in the version, either the 3 in 3.1.4 or the 4 in 0.4.2.
The caret range is used by default when adding a package by running
$ yarn add package-name
This will install the package with its latest stable version, and Yarn writes our package.json
of that version with the caret range.
If I understand this correctly, it seems that if I run yarn
my package in the future, or if some other package depends on a later version, it will use the later version as long as it satisfies the range.
There are more ranges in semantic versioning:
You may read the Yarn's docs here, or NPM's docs here.
Understanding the command yarn upgrade
So what I learned today is that running yarn upgrade
does not necessarily update package.json
as I imagined it would.
yarn upgrade
(without modifier)
Running yarn upgrade
without any modifiers does not update package.json
.
If we run yarn upgrade
without any flags, it will install the latest version that matches the version pattern indicated by package.json
. And it will not update package.json
.
-
yarn upgrade
on dependency"react": "~16.5.1"
: installs the latest version on tilde range with~16.5.1
which is16.5.2
-
yarn upgrade
on dependency"react": "^16.5.1"
: installs the latest version on caret range with~16.5.1
which is16.8.6
as of today -
yarn upgrade
on exact dependency"react": "16.5.1"
does not install anything new at all 🧐
yarn upgrade --latest
Running yarn upgrade
might update package.json
, when the latest stable version no longer matches current range.
But it still might not update package.json
. And specifically, when the latest version matches the semantic version range indicated in package.json
.
-
yarn upgrade --latest
on dependency"react": "~16.5.1"
: installs the latest version16.8.6
as of today, and updatespackage.json
to"react": ~16.8.6"
-
yarn upgrade --latest
on dependency"react": "^16.5.1"
: installs the latest version16.8.6
as of today, and updatespackage.json
to"react": ^16.8.6"
-
yarn upgrade --latest
on exact dependency"react": "16.5.1"
installs the latest version16.8.6
as of today, and updatespackage.json
to"react": 16.8.6"
What should I do if I want to upgrade to a version and update package.json
If dealing with a library where even minor versions are sensitive, it is better to indicate a stricter version range, even an exact one. And upgrade with --latest
.
Other than that, after playing around with a few commands, I find this command interesting and the most straightforward in this situation:
$ yarn upgrade react@^
This will pull up an interactive list of versions for you to select. And after installation, it will update package.json
to the selected version with a caret range again.
Wrapping up
For version sensitive libraries (such as Flow??? 🙈), indicate the version dependency without any ranges.
Use yarn upgrade package@[version]
is perhaps the most intuitive way of the actual action of upgrading packages.
Top comments (17)
Nice article, but there is one little mistake that I found, which is:
yarn upgrade --latest
on dependency"react": "^16.5.1"
: installs the latest version16.8.6
as of today, and DOES NOT update package.json to"react": ^16.8.6"
. AS THE VERSION16.8.6
IS ALREADY IN THE SPECIFIED RANGE^16.5.1
Great write up 👏
I prefer to use
yarn upgrade-interactive --latest
thankfully Oh My ZSH' Git plugin cones with a aliasyui
Anyway, upgrading interactive let's me see and selectively upgrade and it updates package.json as well 🥳
So this there?
This is what I'm trying to answer - I don't feel like this article reached a conclusion on this question... unless the answer is "no"?
yarn upgrade --latest
does not respect version constraints - it installs the latest available versions, even if that conflicts with your constraints:"react": "^16.5.1"
will change it to "react": "^18.2.0" which is not what I wanted.I just want to upgrade to the next compatible version and update my
package.json
.That's not a thing?
(I'm about a week into
yarn
and it's uber frustrating how many little ways it deviates fromnpm
. I hate it. I wish it didn't exist. Why did we have to split the entire ecosystem in two like this? Becauseyarn
used to be faster? ugh.)Okay, so I finally found the answer I was looking for:
yarn upgrade
will respect your version constraints - as opposed toyarn upgrade --latest
, which will most likely break everything.syncyarnlock will transfer the installed version numbers from
yarn.lock
topackage.json
, plain and simple - the--save
option makes it write the changes back topackage.json
, so you cangit diff
and review the results, while--keepPrefix
will preserve the^
or~
operators in your existingpackage.json
version constraints.yarn install
finally will update youryarn.lock
using the updated version constraints - it won't install anything new at this point, but this step is required, or yarn will complain later that youryarn.lock
is outdated with the new version constraints in your updatedpackage.json
.That was fantastic, thanks!!
It's just a weird design of
yarn upgrade
. Anyway thanks for your article which saved my day.I faced a bug because of the old dependencies. Tried
yarn upgrade
, never get it to work.I finally upgraded all my versions in my package.json and solved my problem by removing the version range. And run:
yarn upgrade --latest
That's why yarn.lock is important...
...And are we getting react hooks soon?!
Yup, I had the same problem with
yarn upgrade
.I solved this by mandating specific versions in
package.json
so that there is no ambiguity about what version is installed.But the microversion number changes are supposed to be bug fix patches not expected to change behavior. You want to manage all those by hand? Seems tedious.
thanks for the :
Have been using
yarn upgrade --exact
. The flag forces the command to overridepackage.json
no matter how the version constraint is declared.Actually, discovered that sometimes
package.json
is not being updated.Looks like
yarn add
is more reliable thanyarn upgrade
:The downside it will install a new package if it has not been installed yet.
This technique can be used to upgrade all packages in a given scope:
Simply use
yarn upgrade all
Great if you just want to upgrade this 😉
Good article Wei!! Just clarified my doubt ;)