yarn.lock is the name of the lockfile used by yarn to track dependencies in a project.
Although the file is autogenerated and not meant to be read by a human, the reality is that more often than not you'll
need to understand how the file is structured, to be able to resolve conflicts, provide feedback in Pull Requests, etc.
yarn.lock can be daunting, specially if you have past experience with its NPM counterpart,
However, you'll find
yarn.lock has a much more simpler structure.
yarn.lock is a collection of "dependency
resolution blocks". Each one of the blocks have a format like:
[email protected], clipboard@^2.0.0, clipboard@^2.0.1: version "2.0.4" resolved "https://registry..." integrity sha512-Vw26VSLRpJfBofiVaFb.... dependencies: good-listener "^1.2.2" select "^1.1.2" tiny-emitter "^2.0.0"
Let's go line by line:
[email protected], clipboard@^2.0.0, clipboard@^2.0.1:
That is the header of the block. Is a list of one or more version specifications separated by a comma. They can be fixed
[email protected]) or ranges (
clipboard@^2.0.1). It means that this block applies to any package in your
dependency tree that depends on one of those versions.
This means that all the dependencies specified in the header (
[email protected], clipboard@^2.0.0, clipboard@^2.0.1)
will be resolved with this specific version of the package,
[email protected] in this case.
This has two implications that are worth mentioning:
No matter where in your dependency tree appears
clipboard@^2.0.1, it will always be resolved with
[email protected]. This is not the case when using NPM.
No matter how other packages specify a dependency on clipboard: if it is not one of the 3 versions specified in the header of the block, they will not get
[email protected], they will get something else.
resolved "https://registry..." integrity sha512-Vw26VSLRpJfBofiVaFb....
These two lines specify where the package will be downloaded from, and a checksum that will be used to validate that the package has not been tampered with.
dependencies: good-listener "^1.2.2" select "^1.1.2" tiny-emitter "^2.0.0"
These are the dependencies of this package. Note that yarn doesn't make a difference between
optionalDependencies... That information is already encoded in the
package.json file of the
Note that, technically, there is no need to specify the dependencies here. yarn could extract the same information from
package.json. I believe those dependencies are here to speed up some lookup process, and more importantly, to help
The important part is that for each dependency listed here, there will be another block in
yarn.lock specifying how
that dependency is resolved. But be careful, the format is slightly different: here it is
good-listener "^1.2.2", but
the block defining that package will have
good-listener@^1.2.2 in its title.
As you can see, the content of
yarn.lock is not really complicated. Manually inspecting it can give us a lot of
information about our tree. I have used
Find out who is bringing some dependency. For example, who is importing
[email protected]? Open
yarn.lock, find the relevant block (tip: it will have
acornin the header, and
version: "6.1.1"), and then search for each version range specified in the header (remember to change the syntax, i.e. add the
Find duplicated packages: the best way is to search for part of the URL, for example search for
https://registry.yarnpkg.com/loglevelnext/. For each occurrence of that URL, it means that a different version of the package will be present in your tree.
Continuing with duplicated packages: once you have find all the blocks that install a dependency, you can check their headers to find the versions ranges. It is very useful to find out why a super old version of a package is still present on your tree.