How to update Rust dependencies with Cargo

Rust projects keep dependency intent and resolved crate versions in different files. Cargo.toml describes the version requirements a project accepts, while Cargo.lock records the exact package versions Cargo will build, so dependency updates are usually lockfile changes made through Cargo's resolver.

The normal path is to let cargo update choose newer versions that still satisfy the manifest. Targeting one package with -p keeps the change narrow, while running cargo update without a package refreshes every eligible locked dependency in the workspace.

A SemVer-breaking crate upgrade usually starts with a manifest requirement change before the lockfile can move to the new major version. After Cargo rewrites the lockfile, run cargo check or the project's test command before committing Cargo.lock.

Steps to update Rust dependencies with Cargo:

  1. Check the currently locked package version.
    $ cargo tree -i itoa
    itoa v1.0.11
    └── demo-cli v0.1.0 (/work/demo-cli)

    Replace itoa with the crate that needs a lockfile refresh.
    Related: How to inspect a Rust dependency tree with Cargo

  2. Preview the targeted lockfile update.
    $ cargo update -p itoa --dry-run
        Updating crates.io index
         Locking 1 package to latest Rust 1.96.0 compatible version
        Updating itoa v1.0.11 -> v1.0.18
    warning: not updating lockfile due to dry run

    Run cargo update --dry-run without -p only when the whole lockfile should be refreshed.

  3. Update the package in Cargo.lock.
    $ cargo update -p itoa
        Updating crates.io index
         Locking 1 package to latest Rust 1.96.0 compatible version
        Updating itoa v1.0.11 -> v1.0.18

    cargo update stays inside the version requirements in Cargo.toml. Change the manifest requirement first when the intended upgrade is outside the current SemVer range.

  4. Review the lockfile diff.
    $ git diff -- Cargo.lock
    diff --git a/Cargo.lock b/Cargo.lock
    index d6f47a4..1075852 100644
    --- a/Cargo.lock
    +++ b/Cargo.lock
    @@ -11,6 +11,6 @@ dependencies = [
     
     [[package]]
     name = "itoa"
    -version = "1.0.11"
    +version = "1.0.18"
     source = "registry+https://github.com/rust-lang/crates.io-index"
    -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
    +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
  5. Verify that the dependency tree now resolves the newer package.
    $ cargo tree -i itoa
    itoa v1.0.18
    └── demo-cli v0.1.0 (/work/demo-cli)
  6. Run the project check or test command.
    $ cargo check
        Checking itoa v1.0.18
        Checking demo-cli v0.1.0 (/work/demo-cli)
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21s

    Use cargo test instead when the project has tests that cover behavior from the updated dependency.
    Related: How to check Rust code with Cargo