Question

Automatically Recompile Rust Files with Cargo Watch

rustrust-cargo

Question

How can I make Rust automatically recompile or type-check my project whenever I save a source file?

At the moment, I manually run cargo build or cargo run each time I want to check my code. I would like a command that watches my files and displays updated results in a nearby terminal, similar to sbt ~compile or sbt ~run.

Does Cargo provide this directly, or does Cargo only detect unchanged files and avoid rebuilding them after I manually invoke a command?

Short Answer

Cargo tracks file changes and reuses previous build work, but the core cargo command does not continuously watch your project by itself. Use the external cargo-watch subcommand to run commands such as cargo check, cargo test, or cargo run automatically after files change.

Concept

Cargo has two related responsibilities that are easy to confuse:

  1. Incremental builds: When you run cargo build, cargo check, or cargo run, Cargo examines your project and rebuilds only what needs rebuilding. Unchanged crates and artifacts can be reused.
  2. File watching: A watcher stays running, notices a save event, and starts a command again automatically.

Cargo provides the first behavior. For the second, Rust developers commonly install cargo-watch, a Cargo subcommand supplied by a separate tool.

cargo check is especially useful during development. It parses, type-checks, and validates your Rust code, but normally does not finish producing an executable binary. That makes it faster than cargo build when your immediate goal is feedback about compiler errors.

A watcher does not replace Cargo's dependency tracking. It repeatedly invokes Cargo, and Cargo then decides which files and crates actually require work.

Mental Model

Think of Cargo as a careful workshop inspector. Each time you ask for a build, the inspector checks which parts changed and only reworks the necessary pieces.

A file watcher is an assistant standing beside the workshop door. Whenever you save a file, the assistant asks the inspector to perform the check again.

  • cargo check: inspect the project for Rust errors.
  • cargo build: inspect and construct the program binary.
  • cargo-watch: notice saves and repeatedly ask Cargo to do one of those jobs.
Take Quiz

Syntax and Examples

Install cargo-watch once:

cargo install cargo-watch

Then, from the root directory of a Rust project, watch files and run cargo check after each change:

cargo watch -x check

The -x option means “execute this Cargo subcommand.” Therefore, this is equivalent to repeatedly running:

cargo check

Other useful commands are:

# Rebuild the executable after changes
cargo watch -x build

# Run tests after changes
cargo watch -x test

# Re-run the application after changes
cargo watch -x run

For example, given this program:

fn main() {
    let greeting = "Hello, Rust!";
    println!("{greeting}");
}

Start cargo watch -x check, then change greeting to an invalid value or introduce a type error. After saving, the watcher reruns cargo check and prints the compiler diagnostic in the terminal.

Step by Step Execution

Consider this command:

cargo watch -x check

And this Rust file:

fn double(value: i32) -> i32 {
    value * 2
}

fn main() {
    let result = double(21);
    println!("{result}");
}

The sequence is:

  1. cargo-watch starts and begins monitoring relevant project files.

  2. It invokes cargo check for the initial project state.

  3. Cargo compiles or reuses dependencies and checks the crate.

  4. You change the call to this invalid code and save:

    let result = double("21");
    
  5. The watcher detects the saved file.

  6. It runs cargo check again.

  7. Cargo recognizes that the Rust source changed, checks the affected crate, and reports that "21" is not an i32.

  8. After you correct it to double(21), save again. The next check succeeds.

Cargo avoids unnecessary recompilation during each invocation; the watcher is responsible for automatically starting those invocations.

Real World Use Cases

  • Fast editor feedback: Keep cargo watch -x check open while writing functions, structs, and trait implementations.
  • Test-driven development: Run cargo watch -x test so tests execute after every saved change.
  • Command-line tools: Use cargo watch -x run while modifying a small CLI program and observing its output.
  • Web services: Rebuild or restart a development server after handler, validation, or configuration code changes.
  • Learning Rust: See compiler diagnostics immediately instead of remembering to run a command after each edit.
  • Multi-crate workspaces: Let Cargo determine which workspace crates need checking when a shared crate changes.
Take Quiz

Real Codebase Usage

In a real Rust project, developers usually choose the repeated Cargo command based on the feedback they need:

# Fast compile/type feedback
cargo watch -x check

# Include lints when Clippy is installed
cargo watch -x 'clippy -- -D warnings'

# Re-run unit and integration tests
cargo watch -x test

A common workflow uses two terminals:

  • Terminal 1: cargo watch -x check for immediate compiler feedback.
  • Terminal 2: run the service, a database, frontend tooling, or focused tests as needed.

For applications that must restart a running process, cargo watch -x run can be useful. However, a long-running server may need to exit before the next command can begin. In those cases, a framework-specific development runner or restart tool may be more appropriate.

In CI, do not use a watcher. CI runs finite commands such as cargo test, cargo clippy, and cargo fmt --check, then exits with a pass or failure status.

Common Mistakes

Expecting cargo check to watch by itself

This command checks once and exits:

cargo check

Run it again manually, or use a watcher:

cargo watch -x check

Using cargo run only to find type errors

cargo run

cargo run builds and starts the program. If you only need compiler feedback, prefer:

cargo check

It usually avoids the final linking step needed to create an executable.

Assuming Cargo automatically reruns after a save

Cargo detects changed files when a Cargo command is invoked. It does not remain active and listen for saves by default. Install and run cargo-watch for continuous behavior.

Running the watcher outside the project directory

Start the command where Cargo.toml is located, unless you deliberately provide a manifest path:

cargo watch --manifest-path path/to/Cargo.toml -x check

Forgetting that a running program can block reruns

With cargo watch -x run, a server that runs forever prevents the next run command from starting until the process ends. Use a restart-aware tool or structure the development command accordingly.

Expecting generated or external files to be watched automatically

If your build depends on files outside the normal project tree, configure the watcher with appropriate watch paths or ensure your build process exposes those dependencies clearly.

Comparisons

Command or toolWatches for saves?Main purposeProduces a runnable binary?
cargo checkNoType-check and validate codeUsually no
cargo buildNoCompile the projectYes
cargo runNoBuild and execute the projectYes, then runs it
cargo testNoBuild and execute testsTest binaries
cargo watch -x checkYesRepeatedly type-check after changesUsually no
cargo watch -x runYesRebuild and rerun after changesYes

cargo check versus cargo build is about what Cargo does. cargo-watch versus plain Cargo is about when it does it. You can combine them because cargo-watch triggers a normal Cargo command whenever files change.

Take Quiz

Cheat Sheet

# Install the watcher once
cargo install cargo-watch

# Watch and type-check: best default feedback loop
cargo watch -x check

# Watch and build a binary
cargo watch -x build

# Watch and run tests
cargo watch -x test

# Watch and run the program
cargo watch -x run

# Watch a project whose manifest is elsewhere
cargo watch --manifest-path path/to/Cargo.toml -x check
  • Cargo itself tracks changes during a command invocation.
  • cargo-watch keeps running and invokes Cargo after changes.
  • Prefer cargo check for quick compile and type feedback.
  • Prefer cargo test when validating behavior.
  • Prefer cargo run when you need to execute the updated program.

FAQ

Does Cargo automatically recompile when I save a Rust file?

Not by itself. Cargo notices changed files the next time you run a Cargo command. Use cargo-watch to invoke a command automatically after saves.

What is the Rust equivalent of sbt ~compile?

A close equivalent is:

cargo watch -x check

Use -x build instead if you specifically need a built executable.

Is cargo check faster than cargo build?

Often, yes. cargo check performs compilation and type checking but generally skips the final work of producing a runnable binary.

How do I watch tests in Rust?

Run:

cargo watch -x test

The test suite runs again after relevant files change.

Do I need to reinstall cargo-watch for every project?

No. cargo install cargo-watch installs the subcommand for your user environment. You can use it in multiple Cargo projects.

Why does cargo watch -x run not rerun my server after a save?

A long-running server process may still be occupying the command. The watcher cannot start the next run until the current process exits; use a restart-focused development setup when necessary.

Does a watcher rebuild every dependency on every save?

No. The watcher triggers Cargo, then Cargo's normal dependency tracking determines what needs rebuilding. Unchanged work can be reused.

Take Quiz

Mini Project

Description

Create a small command-line temperature converter and use a file watcher to get immediate Rust compiler feedback while you modify it. This mirrors a practical development loop: save code, automatically check it, then fix any reported errors.

Goal

Build a Rust CLI that converts Celsius to Fahrenheit and verify it automatically with cargo watch -x check.

Requirements

  1. Create a new binary Rust project named temperature_converter.
Take Quiz

Keep learning

Related questions

View more