Coding Standards & API Guidelines
Fleet-wide Rust standards extend defaults with project layout, error handling, unsafe policy, and the official Rust API guidelines for public crates - enforced by rustfmt, clippy -D warnings, and review checklists.
Recipe
Quick-reference recipe card - copy-paste ready.
# Cargo.toml workspace lints (edition 2024 style)
[workspace.lints.rust]
unsafe_code = "forbid" # in domain crates; allow in ffi-shim with ADR
[workspace.lints.clippy]
unwrap_used = "deny"
expect_used = "warn"
await_holding_lock = "deny"crates/
foo-domain/ # no axum, sqlx, tokio in public API
foo-infra/ # IO adapters
foo-api/ # binaryWhen to reach for this:
- New repo bootstrap from template
- Repeated PR debates on style
- Open-sourcing internal crate
- Security audit consistency request
Working Example
//! Domain crate - follows API guidelines: typed errors, no panics in public API.
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ValidateError {
#[error("negative amount: {0}")]
NegativeAmount(i64),
}
/// Returns total in cents - caller owns validation semantics.
pub fn total_cents(subtotal: i64, tax: i64) -> Result<i64, ValidateError> {
if subtotal < 0 || tax < 0 {
return Err(ValidateError::NegativeAmount(subtotal));
}
Ok(subtotal + tax)
}Public functions return Result; binaries map errors to HTTP at edge.
Deep Dive
Rust API Guidelines (selected)
- Naming -
snake_casefunctions,UpperCamelCasetypes, avoid abbreviations. - Ownership - Prefer borrowed args when caller has data; return owned when creating.
- Errors -
thiserrorenums with meaningful variants; noStringerrors in libs. - Docs -
///on public items with examples compiling incargo test --doc. - Features - Optional deps behind feature flags; default features minimal.
Layout Standards
- Workspace for multi-crate services.
tests/integration;benches/for Criterion.#[cfg(test)]unit tests beside code.
Review Checklist
- Public API change semver-appropriate?
-
unsafehas safety comment + second reviewer? - New dep vetted (
cargo deny)? - Tracing on user-visible paths?
Gotchas
- clippy allow wall - Defeats CI. Fix: ADR for crate-level allows with expiry.
- Domain imports axum - Untestable logic. Fix: Forbidden import lint or arch unit test.
- Breaking change in patch - Fix: Semver + changelog automation.
- Doc examples don't compile - Fix:
cargo test --docin CI.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
#![forbid(unsafe_code)] everywhere | Pure domain | FFI shim crate |
| nightly-only fmt rules | Team agrees | MSRV stable CI |
| Custom derive lints | Org-specific API | Upstream clippy covers it |
FAQs
Line width?
100 common default; match rustfmt.toml fleet-wide.
pub use re-exports?
Minimize in public API; prefer explicit paths per API guidelines.
async in public lib API?
Prefer sync or abstract with traits; async fn in traits when stable for your MSRV policy.
Application vs library standards?
Stricter on published crates; binaries may use anyhow at root.
Grandfather violations?
Track in debt tickets; no new violations in touched files (ratchet).
Related
- Rust API Guidelines - detailed rules
- Linting Best Practices - tooling
- Code Review Culture - enforcement
- Unsafe & Dependency Governance - safety
- Documentation Conventions - docs
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+.