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:
- Incremental builds: When you run
cargo build,cargo check, orcargo run, Cargo examines your project and rebuilds only what needs rebuilding. Unchanged crates and artifacts can be reused. - 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.
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:
-
cargo-watchstarts and begins monitoring relevant project files. -
It invokes
cargo checkfor the initial project state. -
Cargo compiles or reuses dependencies and checks the crate.
-
You change the call to this invalid code and save:
let result = double("21"); -
The watcher detects the saved file.
-
It runs
cargo checkagain. -
Cargo recognizes that the Rust source changed, checks the affected crate, and reports that
"21"is not ani32. -
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 checkopen while writing functions, structs, and trait implementations. - Test-driven development: Run
cargo watch -x testso tests execute after every saved change. - Command-line tools: Use
cargo watch -x runwhile 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.
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 checkfor 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 tool | Watches for saves? | Main purpose | Produces a runnable binary? |
|---|---|---|---|
cargo check | No | Type-check and validate code | Usually no |
cargo build | No | Compile the project | Yes |
cargo run | No | Build and execute the project | Yes, then runs it |
cargo test | No | Build and execute tests | Test binaries |
cargo watch -x check | Yes | Repeatedly type-check after changes | Usually no |
cargo watch -x run | Yes | Rebuild and rerun after changes | Yes |
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.
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-watchkeeps running and invokes Cargo after changes.- Prefer
cargo checkfor quick compile and type feedback. - Prefer
cargo testwhen validating behavior. - Prefer
cargo runwhen 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.
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
- Create a new binary Rust project named
temperature_converter.
Keep learning
Related questions
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.