Commit the lockfile for anything you deploy: applications, services and tools. For a library that others depend on, the lockfile mostly does not affect your consumers, so opinions differ, and some ecosystems say not to commit it. Names vary: package-lock.json, Cargo.lock, composer.lock, packages.lock.json, gradle.lockfile, go.sum and pylock.toml.
What each ecosystem calls it
| Ecosystem | Lock or checksum file | Notes from the docs |
|---|---|---|
| npm | package-lock.json | Clean install requires it |
| Rust (Cargo) | Cargo.lock | Created by default for new projects |
| PHP (Composer) | composer.lock | Docs advise committing it for projects |
| .NET (NuGet) | packages.lock.json | Opt in with a project property |
| Gradle | gradle.lockfile | Opt in per configuration |
| Go | go.sum | Records checksums, alongside go.mod |
| Python | pylock.toml | Standard format from PEP 751 |
Two caveats. Go is different in kind: go.mod already states exact minimum versions, and go.sum holds hashes used to verify downloads. Python has several tool specific lock formats, and PEP 751 defines a shared one, which the PEP status page lists as final.
Applications: commit it
The reasons are the same everywhere. A committed lock gives you the same dependencies on every machine and on every day. The Cargo FAQ lists the benefits: deterministic builds, easier bisecting, and CI failures that trace to a commit instead of to a new upstream release. Composer's docs say to commit the lock so CI servers, production machines and teammates all use the same versions.
Libraries: it depends, and the docs differ
The Cargo FAQ notes the lockfile does not affect consumers of your package, since only the manifest does that. Composer's docs say libraries do not need to commit it. NuGet's docs go further and say a library project you do not ship should not check in the lock file, because the consuming application's own resolution decides what is installed.
You may still want a lock in a library repo for your own CI. The Cargo FAQ lists that as a reason to commit. Just do not assume it protects the people who install your library.
Opting in where the lock is not automatic
For NuGet, set the restore property for a lock file, and the project then writes packages.lock.json. For Gradle, call the dependency locking setup, then write the initial lock state with the dependencies task and its write-locks option, and commit gradle.lockfile at each project root.
What to check in review
- Is the lockfile present in the repo?
- Did the manifest change without a matching lock change?
- Does the lock diff show only the packages you expected?
That last check is the human one. A pull request that bumps one dependency should not rewrite two hundred lines of unrelated versions without an explanation.
Safeguard can help here: it scans dependencies and generates SBOMs, applies reachability analysis so you can sort findings by what your code can actually call, and enforces policies and gates on pull requests. You can try a free scan on a repository to see what it finds.
Quick check
Does committing a lockfile protect people who install my library?
Generally no. For Cargo, the FAQ says the lockfile does not affect consumers of your package, only the manifest does.
Is go.sum a lockfile?
Not exactly. It stores checksums that Go uses to verify downloaded modules. Version selection is recorded in go.mod.
Sources
- Cargo FAQ
- Composer basic usage
- NuGet PackageReference
- Gradle dependency locking
- Go modules reference
- PEP 751
- npm ci
Last reviewed: 19 October 2026.