Formatting with rustfmt
rustfmt is the official automatic code formatter for Rust. It parses your source files into an Abstract Syntax Tree (AST) and rewrites them according to the standard Rust Style Guide—normalizing indentation (4 spaces), brace placement, line widths (100 columns max), import ordering, and trailing commas.
Running rustfmt via Cargo and Standalone
In a Cargo project, cargo fmt formats every .rs file in the package or workspace in place:
# Format all Rust source files in the current project
cargo fmt
# Format a single standalone file directly with `rustfmt`
rustfmt main.rs
Before and After rustfmt
Given an inconsistently formatted file messy.rs:
use std::collections::HashMap;
use std::cmp::max;
fn calculate(a:i32,b:i32)->i32{if a>b{a*2}else{max(a,b)+10}}
fn main() {
let mut scores = HashMap::new();scores.insert("Alice", calculate(8, 12));
println!("{scores:?}");}
Running rustfmt --edition 2024 messy.rs rewrites the file in place to standard Rust style:
use std::cmp::max;
use std::collections::HashMap;
fn calculate(a: i32, b: i32) -> i32 {
if a > b { a * 2 } else { max(a, b) + 10 }
}
fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", calculate(8, 12));
println!("{scores:?}");
}
Notice that in the 2024 edition (style_edition = "2024"), rustfmt also sorts use imports using version-sort rules and formats short single-line if expressions compactly when they fit within the width limit.
Common cargo fmt and rustfmt Flags
| Command / Flag | Description |
|---|---|
cargo fmt |
Formats all .rs files in the current package or workspace in place |
cargo fmt --check |
Checks whether all files are formatted; prints a diff and exits with code 1 if any file needs formatting (used in CI pipelines) |
cargo fmt -- --emit stdout |
Prints the formatted output to standard output without modifying files on disk |
rustfmt --edition 2024 file.rs |
Formats a standalone file using the 2024 edition grammar and style rules |
rustfmt --check file.rs |
Verifies that file.rs is already formatted |
rustfmt --print-config default out.toml |
Writes all default configuration options to out.toml for reference |
In continuous integration (CI) workflows such as GitHub Actions, run cargo fmt --check to ensure every pull request adheres to standard formatting:
cargo fmt --check
Diff in /path/to/project/src/main.rs:1:
-fn main(){println!("hi");}
+fn main() {
+ println!("hi");
+}
Key Standard Formatting Rules Applied by rustfmt
| Element | Standard Rule Enforced by rustfmt |
|---|---|
| Indentation | 4 spaces per indentation level (never hard tabs \t unless configured otherwise) |
| Maximum line width | 100 characters (max_width = 100) |
Opening braces { |
K&R / 1TBS style: opening brace stays on the same line as fn, struct, enum, if, match, or loop |
| Multi-line structs, enums, and calls | Adds a trailing comma after the last item when split across multiple lines |
use declarations |
Sorted alphabetically within contiguous groups of imports |
| Binary operators | Single space before and after binary operators (a + b, x = 5) |
| Type annotations | No space before colon, single space after colon (x: i32) |
Configuring rustfmt with rustfmt.toml
To customize formatting rules for a project, create a rustfmt.toml (or .rustfmt.toml) file in the project root directory. rustfmt searches upward from the target source file until it finds this file:
edition = "2024"
style_edition = "2024"
max_width = 100
tab_spaces = 4
hard_tabs = false
newline_style = "Unix"
use_small_heuristics = "Default"
use_field_init_shorthand = true
use_try_shorthand = true
| Configuration Option | Default | Effect |
|---|---|---|
edition |
"2015" (standalone) or from Cargo.toml |
Specifies the language edition used to parse the file |
style_edition |
Matches edition |
Controls edition-gated formatting behavior ("2015", "2021", or "2024") |
max_width |
100 |
Maximum number of characters allowed on a single line before wrapping |
tab_spaces |
4 |
Number of spaces per indentation level |
hard_tabs |
false |
Uses \t tab characters instead of spaces when set to true |
newline_style |
"Auto" |
Line ending format: "Auto", "Unix" (\n), or "Windows" (\r\n) |
use_field_init_shorthand |
false |
Converts Point { x: x, y: y } into shorthand Point { x, y } |
Skipping Formatting on Specific Items (#[rustfmt::skip])
Sometimes a hand-aligned lookup table, matrix literal, or bitfield mapping is much easier to read when its columns are aligned manually. Apply the #[rustfmt::skip] attribute directly above an item, block, or expression to tell rustfmt to leave it untouched:
fn main() {
#[rustfmt::skip]
let rotation_matrix: [i32; 9] = [
0, -1, 0,
1, 0, 0,
0, 0, 1,
];
println!("Matrix: {rotation_matrix:?}");
}
Matrix: [0, -1, 0, 1, 0, 0, 0, 0, 1]
To prevent rustfmt from touching an entire module or source file, place the inner attribute #![rustfmt::skip] at the very top of the file.