How to Update Rust to the Latest Version

Update Rust with rustup update. Manage stable, beta, and nightly toolchains, pin versions per project, install components like rustfmt and clippy.

The day your build stops working

You sit down to work on a Rust project you haven't touched in three months. You hit cargo build and the compiler complains about a dependency that uses a feature your toolchain doesn't have yet. Or you copy-paste a snippet from a blog post and the compiler throws an error about a syntax it claims doesn't exist. The Rust release train moves fast: a new stable version ships every six weeks, and crates on crates.io routinely require recent compilers. Knowing how to update is one of those tiny skills that quietly saves a lot of head-scratching.

The good news: updating Rust is genuinely a one-line command. The slightly longer story is what that command actually does, what it doesn't do, and how to handle the cases where one version isn't enough.

What rustup is and why it matters

When you first installed Rust, you most likely went to rustup.rs and ran the script there. That script installed rustup, which is a toolchain manager. It is not the Rust compiler. The compiler is called rustc, and cargo is the build tool. rustup is the layer above them that decides which versions live on your machine and which one runs when you type cargo build.

Think of it like nvm for Node, or pyenv for Python. You can have multiple Rust toolchains installed side by side: stable, beta, nightly, and any specific past version you pinned for a project. rustup switches between them per-directory using a file called rust-toolchain.toml, or globally with a default setting.

Knowing this layer exists is the trick to understanding what update commands actually do. You're not updating "Rust" as a single thing. You're updating individual toolchains that rustup is keeping track of.

The one command you usually want

# Update rustup itself, then update every toolchain you have installed.
rustup update

That command does two things in sequence. First, it checks whether rustup itself has a newer version and self-updates if so. Second, it walks through every toolchain you've installed (stable, nightly, beta, anything pinned) and pulls the latest version of each.

After it finishes you'll see something like:

info: syncing channel updates for 'stable-x86_64-apple-darwin'
info: latest update on 2024-09-05, rust version 1.81.0 (eeb90cda1 2024-09-04)
info: downloading component 'rustc'
...
  stable-x86_64-apple-darwin updated - rustc 1.81.0 (eeb90cda1 2024-09-04) (from rustc 1.78.0 (9b00956e5 2024-04-29))

The "from" line is what you actually care about. If it says "unchanged," you were already on the latest. If it shows a version bump, you just got six weeks (or whatever time has passed) of compiler improvements, fixed bugs, and new stabilized features.

What if you only want to update one channel

rustup update updates everything. If you only care about stable, you can be specific:

# Update only the stable channel; leave nightly and others alone.
rustup update stable

This is occasionally useful if you intentionally hold an old nightly for reproducibility (some teams do this for tools like rustfmt nightly features) and you don't want a routine update to bump it.

Switching the default toolchain

Updating doesn't change which toolchain is your default. If you've never set one, stable is the default. To switch:

# Make stable the toolchain that runs when you type plain `cargo` or `rustc`.
rustup default stable

# Or pin globally to nightly if you want the bleeding edge.
rustup default nightly

The default is just a setting. You can override it per directory with a file (more on that below) or per command with cargo +nightly build.

Installing a specific older or newer version

Sometimes a project pins to an exact compiler. Maybe a CI matrix builds against three versions to confirm a Minimum Supported Rust Version (MSRV). Maybe a tutorial requires a specific nightly date. The pattern:

# Install a specific stable release by version number.
rustup toolchain install 1.75.0

# Install a nightly from a specific date.
rustup toolchain install nightly-2024-08-15

# Install the beta channel (the next stable, in pre-release form).
rustup toolchain install beta

Once installed, you can use them by passing +name to cargo:

# Run cargo build using the 1.75.0 toolchain just for this command.
cargo +1.75.0 build

# Same idea with nightly.
cargo +nightly check

The + prefix is a rustup thing. It intercepts the call, picks the right toolchain, and forwards the rest of the arguments to that toolchain's cargo.

Pinning a toolchain per project

If you want everyone working on a project (and your CI) to use the same Rust version automatically, drop a rust-toolchain.toml file at the project root:

# rust-toolchain.toml
[toolchain]
# The exact compiler version this project builds with.
channel = "1.81.0"
# Optional: extra components you want auto-installed alongside the compiler.
components = ["rustfmt", "clippy"]
# Optional: cross-compilation targets to add automatically.
targets = ["wasm32-unknown-unknown"]

When anyone runs cargo inside that project, rustup notices the file and will install the listed toolchain on the fly if it's missing. No "works on my machine" arguments about compiler versions.

You'll also see older projects use a one-line file just called rust-toolchain containing only the version string. Both forms still work, but the .toml form is the recommended one going forward because it lets you specify components and targets too.

How the install was set up matters

There's one important caveat. The advice above assumes you installed Rust through rustup. If you installed Rust some other way, the commands may not work, and you should not mix them.

Common alternatives:

  • Homebrew on macOS (brew install rust): updates with brew upgrade rust. No rustup. You're stuck on whatever version Homebrew packages, which is sometimes lagging.
  • Linux distro packages (apt install rustc, dnf install rust): similar story. Updates come with the distro. Often quite old.
  • Snap on Ubuntu: updates automatically. Recent versions, but Snap quirks apply.

If you're doing serious Rust work, the rustup install is what you want. To migrate, uninstall the package-manager version, then run the install script from rustup.rs:

# The official installer. It detects your platform and sets up rustup for you.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

After that, rustup update is your friend forever.

Common pitfalls

You ran rustup update and nothing changed. Two possibilities. Either you're already on the latest (rustup will say "unchanged"), or you don't have rustup at all and the command failed silently because it's missing from your PATH. Run which rustup to check.

You updated and now your project won't compile. This happens occasionally with edition or lint changes. Read the error carefully: the compiler messages in modern Rust are excellent and almost always tell you exactly what changed. If you really need the old version back, rustup default 1.78.0 (or whatever you were on) gets you there. Then upgrade your project's code at your own pace.

You updated nightly and a tool broke. Nightly changes daily. Some tools (notably rustfmt and parts of rust-analyzer) occasionally lag behind a nightly bump for a day or two. The fix is to roll back to a nightly from a few days ago: rustup toolchain install nightly-2024-09-01 and then rustup default nightly-2024-09-01.

You're on Windows and rustup update says permission denied. Usually this is your antivirus holding open a file in the toolchain directory. Close any running Rust processes (including editor language servers) and try again.

Components: rustfmt, clippy, and friends

Rust ships a small set of optional components alongside the compiler. The two everyone uses are rustfmt (the formatter, run via cargo fmt) and clippy (the linter, run via cargo clippy). They're tied to the toolchain version. When you rustup update, the components on your active toolchains update too.

If a component is missing (you'll get "command not found" or "rustfmt is not installed for the active toolchain"), add it:

# Install rustfmt for the currently active toolchain.
rustup component add rustfmt

# Same idea for clippy.
rustup component add clippy

The rust-analyzer language server used to be a component too, but the modern setup is to install it separately as an editor extension or standalone binary. If your editor complains, install it through your editor's plugin system rather than through rustup.

Targets are similar but for cross-compilation. Adding wasm32-unknown-unknown lets you build for the browser; adding aarch64-unknown-linux-gnu lets you build for ARM Linux from an x86 machine.

# Add a target so your active toolchain can build for it.
rustup target add wasm32-unknown-unknown

You don't need this for normal native builds. Only when you want to produce a binary for a different platform than the one you're on.

When to update vs when to hold

For day-to-day development, run rustup update every couple of weeks. The release notes are short, the upgrade is fast, and being on a recent version means crates from crates.io will compile without complaint.

For production builds and CI, pin a specific version with rust-toolchain.toml. You don't want a routine rustup-on-the-CI-runner to silently change which compiler you ship. Bump the pin deliberately, in a PR, with a chance to test.

For libraries you publish, declare an MSRV (Minimum Supported Rust Version) in Cargo.toml and test against it. Updating your dev machine doesn't bump your MSRV automatically: you have to pick a target and build against it.

Where to go next

Cargo and rustup are tightly intertwined, and most "how do I update Rust" questions branch out into "now how do I manage my dependencies?"

How to add dependencies in Cargo.toml

How to Resolve Dependency Conflicts in Cargo

How to Use Dependabot/Renovate for Rust Dependencies