Conventions & Style Guide
Team-wide Rust idioms reduce review friction: rustfmt formatting, clippy policy, naming, module layout, and error handling split.
Recipe
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings# rustfmt.toml (repo root)
edition = "2024"
max_width = 100When to reach for this:
- Writing or reviewing any PR
- Onboarding new hires
- Updating CI lint policy
Working Example
Naming
// modules and files: snake_case
mod billing_tax;
// types: PascalCase
struct LineItem;
// functions: snake_case
fn calculate_tax() {}
// constants: SCREAMING_SNAKE_CASE
const MAX_RETRIES: u32 = 3;Errors
// crates/domain - library
#[derive(thiserror::Error, Debug)]
pub enum DomainError { /* ... */ }
// crates/api - binary
fn main() -> anyhow::Result<()> { Ok(()) }Module layout
src/
lib.rs or main.rs
routes/ # HTTP only in api crate
error.rs
state.rs
Deep Dive
Clippy Policy
| Level | Rule |
|---|---|
| Deny | unwrap_used in production src/ (allow in tests) |
| Deny | pedantic subset team selects |
| Allow | Documented with #[allow(clippy::...)] + reason |
Commit Messages
feat(api): add readiness probe [API-55]
fix(domain): reject zero-quantity line [BILL-12]
Imperative subject, ticket ID, body explains why.
API Documentation
Public items need /// with example compiling in rustdoc:
/// Adds two quantities.
///
/// # Example
/// ```
/// assert_eq!(add(1, 2), 3);
/// ```
pub fn add(a: u32, b: u32) -> u32 { a + b }Gotchas
- Formatting debates in PR - wasted time. Fix: rustfmt auto in CI.
- allow clippy globally - hides real issues. Fix: line-level allows with comment.
unwrapin lib - panics surprise callers. Fix:Resultorexpectwith invariant comment in tests only.- Inconsistent error types per module - fragmentation. Fix: one enum per crate.
- Missing
pub(crate)- over-exposed API. Fix: minimal visibility.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Stricter pedantic | Safety-critical | Early startup velocity |
| Custom rustfmt width | Long generics | Unless team agrees |
FAQs
Edition 2024 required?
When edition = "2024" in workspace Cargo.toml; match manifest, not blog posts.
Import order?
rustfmt handles groups; rust-analyzer organize imports on save optional.
Related
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+.