Skip to content
LatchkeyLatchkey home

What Is a Lockfile and Why Should You Commit It?

A lockfile records the exact resolved version (and hash) of every dependency, direct and transitive. Commit it and everyone - including CI - builds against the identical dependency tree.

Manifest files like package.json declare version *ranges*; a lockfile records the exact versions those ranges resolved to. That distinction is the difference between a reproducible build and "it broke and nothing changed".

Manifest vs lockfile

A manifest says "I want lodash ^4.17.0" - a range. A lockfile says "lodash resolved to exactly 4.17.21, with this integrity hash" - and does the same for every transitive dependency. The manifest captures intent; the lockfile captures the exact realized tree.

Why commit it

  • Reproducibility: every machine installs the identical versions.
  • Stability: a new patch release of a transitive dep cannot silently break CI.
  • Security: integrity hashes let the installer verify packages were not tampered with.
  • Cacheability: a stable lockfile is the natural, reliable cache key.

What happens without one

If the lockfile is gitignored or missing, each install re-resolves the ranges against the latest matching versions. Two runs days apart can get different transitive dependencies, producing the classic "passes on my machine, fails in CI" with no code change. Caching also degrades because there is no stable key.

Using it correctly in CI

Use the frozen/clean-install mode that installs strictly from the lockfile and fails on drift (npm ci, yarn --frozen-lockfile, pip install --require-hashes, cargo build --locked). That guarantees CI builds exactly what the lockfile specifies and flags any drift instead of silently resolving around it.

Key takeaways

  • A lockfile pins exact versions and hashes for the whole dependency tree.
  • The manifest is intent (ranges); the lockfile is the realized result.
  • Commit it for reproducibility, stability, security, and cacheability.
  • Use frozen-install modes in CI so drift fails loudly.

Frequently asked questions

What is What is a lockfile and why should you commit It??
Manifest files like package.json declare version *ranges*; a lockfile records the exact versions those ranges resolved to. That distinction is the difference between a reproducible build and "it broke and nothing changed".
Manifest vs lockfile?
A manifest says "I want lodash ^4.17.0" - a range. A lockfile says "lodash resolved to exactly 4.17.21, with this integrity hash" - and does the same for every transitive dependency. The manifest captures intent; the lockfile captures the exact realized tree.
What happens without one?
If the lockfile is gitignored or missing, each install re-resolves the ranges against the latest matching versions. Two runs days apart can get different transitive dependencies, producing the classic "passes on my machine, fails in CI" with no code change. Caching also degrades because there is no stable key.
Using it correctly in CI?
Use the frozen/clean-install mode that installs strictly from the lockfile and fails on drift (npm ci, yarn --frozen-lockfile, pip install --require-hashes, cargo build --locked). That guarantees CI builds exactly what the lockfile specifies and flags any drift instead of silently resolving around it.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card