cargo check
The cargo check command runs the front-end and middle-end passes of rustc—parsing, macro expansion, name resolution, type checking, trait solving, and borrow checking—while skipping machine-code generation (LLVM codegen) and binary linking. Because LLVM code generation and linking typically account for 50–80% of total compilation time, cargo check validates your code in a fraction of the time of cargo build.
`rustc` Compilation Pipeline:
[ Lex / Parse / Expand Macros ]
|
v
[ Name Resolution & Type Inference (HIR) ]
|
v
[ Borrow Checker & Lints (MIR) ] <=== `cargo check` STOPS HERE!
| (Emits `.rmeta` metadata file only)
v
[ LLVM Optimization & Codegen ]
|
v
[ Native Linker (`ld` / `lld`) ] <=== `cargo build` runs all the way here
Comparing cargo check and cargo build
| Aspect | cargo check (cargo c) |
cargo build (cargo b) |
|---|---|---|
| Syntax & Macro Checking | Yes | Yes |
| Type & Trait Checking | Yes | Yes |
| Borrow & Lifetime Checking | Yes | Yes |
| Compiler Warnings & Lints | Yes | Yes |
| LLVM Machine Code Generation | No (Skipped) | Yes |
Executable Binary / .rlib Output |
No (Writes .rmeta type metadata only) |
Yes (Writes .rlib and executables) |
| Typical Incremental Speed | 2x–5x faster | Baseline |
Useful cargo check Flags for Comprehensive Validation
By default, cargo check only checks the package's library and binary targets (src/lib.rs and src/main.rs). If you refactor a public function signature, a compile error sitting inside tests/integration.rs or examples/demo.rs will not be checked unless you pass --all-targets (or --tests):
# 1. Check library, binaries, unit tests, integration tests, examples, and benches:
cargo check --all-targets
# 2. Check across every crate in a workspace with all Cargo features enabled:
cargo check --workspace --all-targets --all-features
# 3. Check whether code compiles cleanly for a different target OS without linking:
cargo check --target x86_64-pc-windows-gnu
What cargo check Cannot Catch
Because cargo check stops before LLVM codegen and linking, there are two rare error classes that only appear during cargo build or cargo test:
- Linker errors: Missing native C libraries (
-l foo) or unresolvedextern "C"symbols. - Post-monomorphization errors: Compile-time
const { assert!(...) }failures inside generic functions that are only instantiated during monomorphization in codegen.
pub fn validate_frame_bounds(offset: usize, len: usize, total: usize) -> Option<usize> {
let end = offset.checked_add(len)?;
(end <= total).then_some(end)
}
fn main() {
println!("Validated end offset: {:?}", validate_frame_bounds(10, 20, 50));
}
Validated end offset: Some(30)