# What Is a Lockfile and Why Should You Commit It?

> A lockfile pins the exact versions of every dependency so builds are reproducible. Learn why committing it is essential for reliable, cacheable CI.

Source: https://latchkey.dev/learn/ci-cd-concepts/what-is-a-lockfile  
Updated: 2026-06-25

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.

## FAQ

### 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.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
