Cargo.lock records the exact version or commit of every dependency, so two builds of the same code get the same inputs. Cargo.toml only states what is acceptable. Commit the lockfile for applications, update on purpose, and remember that yanking a crate version does not change builds that already have a lockfile.
What is the difference between Cargo.toml and Cargo.lock?
The Cargo guide puts it plainly. Cargo.toml describes your dependencies in a broad sense and is written by you. Cargo.lock holds exact information about them and is maintained by Cargo, not edited by hand. When in doubt, the guide says to check Cargo.lock into version control.
The guide's example uses a Git dependency with no revision. Cargo takes the latest commit the first time you build and writes that commit hash into Cargo.lock. Anyone who builds from your lockfile gets the same commit, even though Cargo.toml never named it. When you want newer code, you run cargo update, or you update one package by name.
What does a requirement like "1.2" really allow?
Cargo version requirements default to caret behaviour. The reference says dependencies are specified with a leading caret, and leaving the caret off is equivalent. So a requirement of 1.2.3 accepts any compatible newer version under the semantic versioning rules. Without a lockfile, a fresh resolve could choose a new release you never tested.
The lockfile is what turns "compatible range" into "this exact version". That is why the same Cargo.toml can give different builds on different days if nobody committed the lock.
Constructed example: a service pins nothing and ships without Cargo.lock. A dependency publishes a patch release that contains a build script change. The next CI run resolves to it automatically, and the build output changes with no pull request to review. With a committed lockfile, the change only arrives when someone runs an update, and the diff shows it.
What does yanking do?
Yanking marks a published version so Cargo does not pick it by default when resolving. The cargo yank documentation is clear about its limits:
- Existing lockfiles are not affected, and direct downloads still work.
- Yanking cannot stop leaked credentials from spreading. If you leaked a secret, revoke it.
- For security vulnerabilities, the documentation says RustSec is typically a less disruptive way to inform users and encourage upgrades.
- A common pattern is to publish a compatible fixed version first, then yank the bad one, so dependents are less likely to fail to compile.
The same page includes a table showing how Cargo chooses a version in the absence of a lockfile after a yank: an exact requirement fails if that exact version is yanked and no lock exists, while a range moves to another compatible version. In short, projects with lockfiles keep building the yanked version, and projects without them move.
How do you update on purpose?
Treat dependency updates as reviewed changes. Run an update, read the lockfile diff, run tests, and commit. Pair this with an advisory check so a yank or a RustSec notice leads to an actual update on your side, because the registry will not do it for you.
What to do
- Commit Cargo.lock for every binary and service.
- Build in CI with the locked flag so a drifted lockfile fails the build instead of silently re-resolving.
- Run updates as their own pull request and review the lockfile diff.
- Check new versions for build scripts and procedural macros, since they run code at build time.
- Subscribe to RustSec advisories for the crates you use and act on them yourself.
- If you publish crates, publish a fixed version before yanking and revoke any leaked tokens.
- Keep registry tokens in your CI secret store, passed through the registry token environment variable, not in files.
Safeguard's SBOM and dependency scanning read lockfiles to list what you ship, and its reachability analysis helps decide which advisories matter first.
Quick check
Should a library commit Cargo.lock?
The Cargo guide says to commit it when in doubt and points to its FAQ for the alternatives. Applications and services should always commit it.
Does yanking remove a bad version from my build?
Not if you have a lockfile that already uses it. Yanking stops new resolution from choosing it by default. You must update your lockfile.
Sources
- Cargo.toml vs Cargo.lock, The Cargo Book, fetched 18 October 2026
- cargo yank, The Cargo Book, fetched 18 October 2026
- Specifying dependencies, The Cargo Book, fetched 18 October 2026
Last reviewed: 18 October 2026.