EMZETT.
Login

Lockfiles and reproducible builds: The same versions everywhere

In short: A lockfile records the exact installed versions of all packages so that development, CI and production use the same state and builds remain reproducible.

In more detail: In package.json it says "express": "^4.18.0", meaning “4.18.0 or newer 4.x”. Without further measures every machine installs different versions depending on the time: “it works on mine” becomes a problem. The lockfile solves that.

In Depth

What is in it?

A lockfile contains all direct and transitive dependencies with exact version, checksum (hash) and origin. Examples: package-lock.json (npm), pnpm-lock.yaml, yarn.lock, Cargo.lock (Rust), poetry.lock/uv.lock (Python), Gemfile.lock, composer.lock, go.sum. It is generated by the tool, not edited by hand.

Using it correctly

  • Commit the lockfile to the repository (for applications; for libraries depending on convention, sensible for CI).
  • In CI and deployment install with the lockfile: npm ci (instead of npm install), pip install -r requirements.txt --require-hashes, cargo build --locked. npm ci aborts if lockfile and package.json do not match.
  • Run updates deliberately (npm update, Dependabot/Renovate), review changes in the lockfile in the pull request.
  • Merge conflicts in the lockfile: do not merge by hand; resolve package.json and let the lockfile be regenerated.

Reproducible builds

Goal: same inputs → same result (bit for bit). For this: lockfiles, pinned tool versions (.nvmrc, .tool-versions, engines), containers with fixed base images (digest instead of latest), no timestamps in the build, deterministic ordering. This eases troubleshooting, rollbacks, security checks (SBOM, signatures) and the confidence that a published artifact matches the source code.

Security

Lockfiles with hashes protect against a package being swapped afterwards. Check manipulated lockfiles in pull requests (different registry URL). Use private registries/proxies (Artifactory, Verdaccio) for control. You avoid dependency confusion with clear namespaces (scopes) and registry configuration.

See also: Semantic versioning, Dependabot and Renovate, Dependencies and libraries