Skip to content

/flags/cargo/cargo-build-locked

cargo build --locked: fail if Cargo.lock needs to be updated

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · cargo 1.98.1 (797e8a9bc 2026-08-05)updated
tool
Cargo
command
cargo build
flag
--locked, --frozen, --offline
default
off (Cargo updates Cargo.lock when Cargo.toml changed)

cargo build --locked requires Cargo.lock to be up to date: if Cargo would have to add, remove or change any entry, the build stops with an error instead of rewriting the lockfile. Use it in CI and release builds so the binary is compiled with exactly the dependency versions that were committed. --frozen adds --offline on top, and cargo install --locked makes installs use the crate's own lockfile.

A stale lockfile

First without any lockfile, then with a path dependency added to Cargo.toml after Cargo.lock was generated (no network is needed):

bash
cargo new -q --vcs none app && cd app
cargo new -q --vcs none --lib util
echo "--- no Cargo.lock yet"
cargo build -q --locked 2>&1 | sed -E 's#[^ ]*Cargo[.]lock#Cargo.lock#'; echo "exit: ${PIPESTATUS[0]}"
cargo build -q; echo "plain build writes Cargo.lock, exit: $?"
cat >> Cargo.toml <<'EOT'
util = { path = "util" }
EOT
echo "--- cargo build --locked after adding a dependency"
cargo build -q --locked 2>&1 | sed -E 's#[^ ]*Cargo[.]lock#Cargo.lock#'; echo "exit: ${PIPESTATUS[0]}"
cargo build -q; echo "plain build updates Cargo.lock, exit: $?"
cargo build -q --locked; echo "locked again, exit: $?"

Output

--- no Cargo.lock yet
error: cannot create the lock file Cargo.lock because --locked was passed to prevent this
help: to generate the lock file without accessing the network, remove the --locked flag and use --offline instead.
exit: 101
plain build writes Cargo.lock, exit: 0
--- cargo build --locked after adding a dependency
error: cannot update the lock file Cargo.lock because --locked was passed to prevent this
help: to generate the lock file without accessing the network, remove the --locked flag and use --offline instead.
exit: 101
plain build updates Cargo.lock, exit: 0
locked again, exit: 0

Both cases exit with 101: Cargo may neither create a missing lockfile nor add the new entry. A plain build does either, after which --locked passes. The sed shortens the absolute lockfile path.

The three flags

FlagCargo.lock may changeNetwork allowedTypical use
(none)YesYesLocal development
--lockedNoYes (downloads locked versions)CI, release builds, cargo install
--offlineYes, from cached crates onlyNoAir-gapped machines, planes
--frozenNoNoHermetic builds after cargo fetch

All Cargo commands that resolve dependencies accept them: build, check, test, run, doc, install, fetch, package. The environment variable CARGO_NET_OFFLINE=true is the config equivalent of --offline.

cargo install --locked

bash
cargo install ripgrep --locked

Without --locked, cargo install re-resolves the crate's dependencies to their newest semver-compatible versions, so an install can fail or behave differently from the author's release build. Many projects document --locked in their install instructions for that reason.

CI recipe

bash
cargo fetch --locked          # download exactly what Cargo.lock lists
cargo build --frozen --release
cargo test --frozen

cargo fetch warms the cache with network access; the build and tests then run without it.

Pitfalls

  • A Rust toolchain upgrade can change the lockfile format version; an old toolchain in CI then sees the lockfile as needing changes. Pin the toolchain with rust-toolchain.toml.
  • --locked with a missing Cargo.lock fails too, as the first run shows, so commit the lockfile before turning the flag on in CI.
  • Workspaces share one Cargo.lock at the root; editing any member's Cargo.toml can make --locked fail for the whole workspace.
  • The flag does not check for yanked or vulnerable versions; use cargo audit for that.

FAQ

What is the difference between --locked, --offline and --frozen?

--locked forbids changes to Cargo.lock. --offline forbids network access. --frozen is both at once: the lockfile must be up to date and Cargo must not touch the network.

Why should I use cargo install --locked?

cargo install ignores the Cargo.lock published with a crate by default and resolves the newest compatible dependencies, which can break the build. --locked uses the author's lockfile, the versions they tested.

Should a library commit Cargo.lock?

Current Cargo guidance is to commit it for libraries too, so CI and contributors get reproducible builds. Consumers of the library still resolve their own versions; your lockfile is not used by them.

Sources