rustfmt
rustfmt (via cargo fmt) enforces consistent Rust formatting so reviews focus on behavior, not brace placement.
Recipe
cargo fmt
cargo fmt --check# rustfmt.toml
edition = "2024"
max_width = 100
imports_granularity = "Module"When to reach for this: Every Rust project; run on save locally and --check in CI.
Working Example
# rustfmt.toml at repo root
edition = "2024"
max_width = 100
newline_style = "Unix"
use_small_heuristics = "Max"- run: cargo fmt --all -- --checkWhat this demonstrates:
editionaligns formatter with language edition--checkfails CI on drift without writing filesrustfmt.tomlapplies workspace-wide when at rootcargo fmt --allincludes workspace members
Deep Dive
Common Options
| Option | Effect |
|---|---|
max_width | Line wrap column |
chain_width | Method chain breaking |
format_code_in_doc_comments | Format doctests |
group_imports | Merge/use import style |
Editor Integration
- rust-analyzer
rust-analyzer.rustfmt.extraArgs - Format on save in VS Code / Cursor with rust-analyzer
- Pre-commit hook:
cargo fmt --check
Gotchas
- Different rustfmt versions - CI vs local diff noise. Fix: pin toolchain in
rust-toolchain.tomlto 1.97.0. - Generated files formatted - merge pain. Fix: exclude in
rustfmt.tomlignorepaths or do not commit generated sources. - Macro-heavy code ugly - rustfmt limitations. Fix:
#[rustfmt::skip]sparingly with comment why. - Skipping fmt in PR - style debates return. Fix: zero tolerance
--checkon main. - Edition mismatch - wrong import reorder rules. Fix:
edition = "2024"in rustfmt.toml matchesCargo.toml.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Manual style guide | Never for Rust teams | Always - use rustfmt |
dprint with rust plugin | Polyglot repos | Pure Rust workspace |
#[rustfmt::skip] | FFI layout-critical blocks | Entire modules |
FAQs
Where put rustfmt.toml?
Repo root for workspaces; applies to all members unless overridden per crate.
fmt vs clippy?
fmt is style only; clippy is lint logic. Run both in CI.
Format tests directory?
Yes - cargo fmt --all includes tests and benches.
How ignore one file?
ignore = ["src/ffi/generated.rs"] in rustfmt.toml.
Does fmt change semantics?
No - only whitespace and import order; still run tests after large reformats.
rustfmt on stable?
Ships with Rust 1.97 toolchain; no separate install.
CI on Windows?
Set newline_style = "Unix" for consistent line endings in snapshots and fmt.
Format before commit?
pre-commit hook or editor format-on-save; CI --check as backstop.
Workspace member override?
Nested rustfmt.toml in member crate overrides root for that crate only.
fmt in merge conflicts?
Re-run cargo fmt after resolving; avoid hand-aligning braces.
Related
- Clippy - linting companion
- Pre-commit & Editor Setup - local workflow
- Linting in CI - pipeline
- Linting & Formatting Best Practices - team policy
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.