Why Running `yarn upgrade` Does Not Update My `package.json`
Published: 2019-04-22 18:29:07

# 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

```shell
yarn upgrade react
```

And it seems everyone was happy.

![](https://i.imgur.com/tlJH8KR.png)

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](https://www.google.com/search?q=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](https://yarnpkg.com/en/docs/managing-dependencies#toc-upgrading-a-dependency) 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.

![](https://i.imgur.com/ekEn1dG.png)

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](https://yarnpkg.com/en/docs/dependency-versions#toc-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

```shell
$ 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:

- [caret ranges](https://yarnpkg.com/en/docs/dependency-versions#toc-caret-ranges)
- [tilde ranges](https://yarnpkg.com/en/docs/dependency-versions#toc-tilde-ranges)
- [hyphen ranges](https://yarnpkg.com/en/docs/dependency-versions#toc-hyphen-ranges)
- [x ranges](https://yarnpkg.com/en/docs/dependency-versions#toc-x-ranges)

You may read the Yarn's docs [here](https://yarnpkg.com/en/docs/dependency-versions), or NPM's docs [here](https://docs.npmjs.com/files/package.json#dependencies).

## 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 is `16.5.2`
- `yarn upgrade` on dependency `"react": "^16.5.1"`: installs the latest version on _caret range_ with `~16.5.1` which is `16.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 version `16.8.6` as of today, and updates `package.json` to `"react": ~16.8.6"`
- `yarn upgrade --latest` on dependency `"react": "^16.5.1"`: installs the latest version `16.8.6` as of today, and updates `package.json` to `"react": ^16.8.6"`
- `yarn upgrade --latest` on _exact_ dependency `"react": "16.5.1"` installs the latest version `16.8.6` as of today, and updates `package.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:

```shell
$ 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.

![](https://i.imgur.com/v1kub69.png)

## 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.

## References

- [Yarn documentation: Versions of dependencies](https://yarnpkg.com/en/docs/dependency-versions)
- [yarn upgrade.js source code](https://github.com/yarnpkg/yarn/blob/82d5891f3726abf275c9753b97bdcc54e85637f3/src/cli/commands/upgrade.js)
- [npm-package.json](https://docs.npmjs.com/files/package.json)