In a Yarn 1 yarn.lock file, each entry starts with one or more name and range pairs, followed by the single version Yarn actually installed. To find the real version of a package, read the version line under the entry whose header matches the range some package.json asked for, not the range itself.
The shape of an entry
The Yarn 1 documentation shows the format. A header lists every range that resolves to the same install, for example package-4@^4.0.0, package-4@^4.5.0, and underneath sit version, resolved (the tarball URL with a hash fragment), and a dependencies block listing that package's own ranges.
That detail matters for security work. Two different packages in your tree can ask for ^4.0.0 and ^4.5.0 of the same library, and Yarn can satisfy both with one version, here 4.6.3. A scanner that reads only package.json sees two ranges. A scanner that reads the lockfile sees one concrete version to check against advisories.
Why the range alone is not enough
A range describes what is allowed, not what is installed. ^4.0.0 allows anything from 4.0.0 up to but not including 5.0.0. Whether your build holds 4.0.1 or 4.9.2 depends on when the lock was last updated. An advisory that says versions before 4.6.0 are affected is answered by the lock entry, not by the range.
The docs also state that Yarn uses only the top level yarn.lock and ignores lockfiles that exist inside dependencies. So a library you consume can ship its own lockfile and it changes nothing about your tree. The top level file records the whole tree.
Steps to check one package by hand
- Open yarn.lock and search for the package name followed by an at sign.
- Find every header line that lists that name. There may be several entries if different ranges resolved to different versions.
- Read the
versionunder each. Each is a distinct installed copy. - Compare each version to the affected and fixed versions in the advisory.
- To see who asked for it, search for the name inside
dependenciesblocks of other entries.
| What you read | What it tells you |
|---|---|
| Header ranges | Every request that this entry satisfies |
version | The version installed in your tree |
resolved | Where the tarball came from, with a hash fragment |
dependencies | The ranges this package asks for in turn |
Things that trip people up
Do not edit the file by hand to bump a version. The Yarn docs say the file is auto generated and should be handled entirely by Yarn, because editing it directly is easy to get wrong. Change package.json or use the Yarn command, then let Yarn rewrite the lock.
Commit the file. The same docs recommend checking yarn.lock into source control for applications and for libraries, because it gives the same tree on every machine. A missing lockfile means every install may pick different versions, and a scan taken on Monday may not describe Tuesday's build.
Note too that this page describes Yarn 1 (Classic). The docs themselves point Yarn 2 and later readers to a separate site, and the file format differs, so confirm which Yarn your repository uses before applying these steps.
Try it yourself
Open the demo and look at how a dependency inventory lists a package once with the version that is actually resolved, then think about how that compares with the ranges in a manifest.
Click through it at your own pace, or open it full screen.
Safeguard's SBOM and dependency scanning builds an inventory of what your projects resolve to. You can run a free scan on a repository and compare the result with your own reading of the lockfile.
Quick check
Can one yarn.lock entry cover two different ranges?
Yes. In Yarn 1 the header can list several ranges separated by commas, and they all resolve to the one version shown under it.
Does a lockfile inside a dependency affect my install?
No. The Yarn 1 docs say only the top level yarn.lock is used and nested ones are ignored.
Should I hand edit yarn.lock to fix a vulnerable version?
No. Change package.json or use the Yarn command and let Yarn regenerate the file, then review the diff.
Sources
Last reviewed: 19 October 2026.