101% more reported CVEs per day in 2026 than last year.

Dependencies

What is a lockfile?

A lockfile records the exact version of every dependency a package manager resolved, direct and transitive, so the next install gets the same tree. It is the best plan you have for a build. It is not a record of what the build actually used.

Updated

What a lockfile records

Your manifest, such as package.json or pyproject.toml, lists the packages you depend on and the version ranges you accept. The package manager turns those ranges into exact versions for the whole tree, including transitive dependencies, and writes the result to the lockfile. npm's documentation describes package-lock.json as describing "the exact tree that was generated, such that subsequent installs are able to generate identical trees".

A single entry in package-lock.json looks like this:

"node_modules/raw-body": {
  "version": "3.0.0",
  "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
  "integrity": "sha512-...",
  "dependencies": {
    "bytes": "3.1.2",
    "http-errors": "2.0.0",
    "iconv-lite": "0.6.3",
    "unpipe": "1.0.0"
  }
}
  • version is the exact version chosen.
  • resolved is where it was fetched from: a registry tarball URL, or a git URL with a commit.
  • integrity is a Subresource Integrity hash of the tarball, so a tampered download fails.
  • dependencies are its own dependencies, which is how the tree, or dependency graph, is stitched together.

Lockfiles by package manager

Package manager Lockfile Install without changing it
npmpackage-lock.jsonnpm ci
Yarn (Berry)yarn.lockyarn install --immutable
pnpmpnpm-lock.yamlpnpm install --frozen-lockfile
uvuv.lockuv sync --locked
Poetrypoetry.lockpoetry install
CargoCargo.lockcargo build --locked
BundlerGemfile.lockbundle config set frozen true
Go modules go.mod versions and go.sum checksums Build commands do not update go.mod by default

With plain pip, the common stand-in is a requirements.txt with exact versions. It pins what it lists, but anything it leaves out is resolved again on every install.

Use frozen installs in CI

A lockfile only helps if the build installs from it. A plain npm install can update package-lock.json when it no longer matches package.json, so the build quietly resolves a new tree. npm ci is built for automated environments:

  • It requires a package-lock.json or npm-shrinkwrap.json.
  • If the lockfile and package.json disagree, it exits with an error instead of updating the lock.
  • It removes any existing node_modules first.
  • It never writes to package.json or the lockfile.

The other commands in the table above do the same job for their package managers.

Apps and libraries

Commit the lockfile for applications and anything you deploy. For libraries, it only locks your own development and CI: npm never publishes package-lock.json and ignores it anywhere but the root project. The applications that install your library resolve its dependencies themselves, within your version ranges. The one npm exception is npm-shrinkwrap.json, which is published and takes precedence, and which most libraries should not use.

Why a lockfile is not a record of what shipped

A lockfile is the plan for one package manager in one project. The build that produced your release did more than follow that plan:

  • It may not have used it. A non-frozen install, a missing lockfile or a second lockfile in a monorepo means the tree was resolved differently from the file you are looking at.
  • Caches. Packages restored from a CI cache are installed without being fetched, and a cache restored by a partial key can predate the current lockfile. See what the GitHub Actions cache hides.
  • Build tools. Setup actions, compilers, linters and code generators arrive through other channels, with their own dependency trees.
  • Downloads and install scripts. A curl in a build step or a package's install script fetches code no lockfile lists.
  • Base images. A container build pulls images and operating system packages that live outside every language lockfile.

The integrity hashes do not help with any of this. They prove that the packages in the lockfile were not tampered with; they say nothing about what the build fetched outside it. SCA tools that turn a lockfile into an SBOM inherit the same blind spots.

Record the build, keep the lockfile

Keep committing lockfiles and installing from them with frozen installs. They make builds repeatable. For the record of what a release contains, CRACI records the build itself: a package-aware proxy on its GitHub Actions runners records every package each job fetches, including packages restored from CI caches, and each job's SBOM states its own completeness. That record gives a more complete view of the dependencies in use than a scan of the lockfile. See build-time SBOMs, or book a demo to compare the two on one of your own builds.

Lockfiles: frequently asked questions

What is a lockfile?

A lockfile is a file a package manager writes to record the exact version of every dependency it resolved, direct and transitive, along with where it came from and a checksum. Later installs read it to reproduce the same tree instead of resolving version ranges again.

Should I commit my lockfile?

Yes, for applications and anything you deploy. Without a committed lockfile, every fresh install resolves version ranges again and can pick up new transitive versions. Commit it and install from it with a frozen install such as npm ci in CI.

Does a lockfile pin transitive dependencies?

Yes. That is its main job. The manifest only lists your direct dependencies and their allowed ranges; the lockfile records the exact version chosen for every package in the tree.

Do lockfiles apply to libraries I publish?

Not for your users. npm, for example, never publishes package-lock.json and ignores it anywhere but the root project. The applications that install your library resolve its dependencies themselves, within the ranges your package.json allows.

What does the integrity field in package-lock.json do?

It holds a Subresource Integrity hash, usually sha512, of the package tarball. npm checks the downloaded package against it, so a tampered tarball for a locked version fails to install. It protects the packages in the lockfile, not anything the build fetches outside it.

Is a lockfile the same as an SBOM?

No. A lockfile is an input: the plan a package manager follows for one project. An SBOM is an inventory of a release. SCA tools often turn a lockfile into an SBOM, which works when the build installed exactly the lockfile and nothing else.

Compare your lockfile with your build

Run one workflow on CRACI and set its recorded SBOM of fetched packages next to what your lockfile says.

Book a demo