When Yarn introduced a lock file (similar to Gemfile.lock
), it did it with an unexpected twist. If you need reproducible builds, yarn.lock
is not enough.
What is a lock file? Lock files ensure that the defined dependencies from files such as package.json
get pinned to specific versions. This later ensures parity on developers’ workstations, CI, and production.
Many people probably depend on Yarn doing the right thing and installing only the pinned versions from yarn.lock
on yarn install
. But, unfortunately, this is not the case…
The default behavior of yarn install
is that the yarn.lock
file gets updated if there is any mismatch between package.json
and yarn.lock
. Weird, right?
(In comparison, other package managers such as RubyGems would only ever look at lock files and install the pinned versions from there.)
Luckily a solution exists. The documentation for the Classic Yarn (1.x) says:
If you need reproducible dependencies, which is usually the case with the continuous integration systems, you should pass –frozen-lockfile flag.
So your yarn install
command for CI and production should look like this:
$ yarn install --silent --production=true --frozen-lockfile
There is a long-standing issue for making this a default, but the developers decided to leave it for a new Yarn version which is developed under the name Berry.
Some also say that you don’t need it as you can use pinned versions directly in package.json
. This only true to some extend, though, because you would have to specify all transitive dependencies as well.
If you still run without the --frozen-lockfile
flag, fix it today. It will save you some headaches later.
Also note, that the --frozen-lockfile
flag is changed to --immutable
in modern versions of Yarn and it’s a default for CI mode.