Rust Patterns Best Practices
APIs that are hard to misuse encode invariants in types, use explicit errors, and reserve interior mutability for documented cases.
How to Use This List
- Apply in API design reviews and domain crate scaffolding.
- Pair with Rust API Guidelines.
- Check items when refactoring Java/C# style into idiomatic Rust.
A - Types and API
- Newtype IDs and validated strings.
UserId,Emailnot rawu64/Stringin public API. - From/TryFrom for conversions. Not ad-hoc
parse_xmethods everywhere. - Builder or typed constructor for complex config. Validation in one place.
- Typestate or enums for protocols. Illegal states unrepresentable where cheap.
- Extension traits for ergonomics on foreign types. Keep in
preludemodule.
B - Errors and Safety
- Libraries return
Result, apps log context. Nounwrapin library public paths. - thiserror for library errors, anyhow for binaries. Consistent workspace policy.
- Document
# Panics,# Errors,# Safetyon public items. rustdoc sections filled. - RAII for locks, files, timers. Scope guards over manual cleanup calls.
- Avoid
Rc<RefCell>graphs without diagram. Prefer arenas or unique ownership.
C - Performance Idioms
- Borrow and
Cowbeforeclone. Clone at task boundary once. - Iterator adapters over manual index loops unless profiled loop wins.
- Pre-size collections when size known.
with_capacity. - Share immutable data with
Arc<str>/Arc<[u8]>. NotArc<String>churn. - Interior mutability: atomics/Mutex documented. Tokio mutex in async shared state.
D - Async and Concurrency
- Shared state
Arc+tokio::sync::Mutexor channels. NotRefCellacross tasks. - No blocking in async without
spawn_blocking. Document thread pool limits. - Semaphores for backpressure. Unbounded channels are a smell.
- Join handles awaited or detached intentionally. No leaked orphan tasks.
- Graceful shutdown pattern. Cancellation tokens and drain.
E - Review Culture
- PR checklist cites pattern choice. Why builder vs literal, why newtype.
- Anti-pattern grep in review.
unwrap(,.clone()in hot files flagged. - Examples in rustdoc compile. Doctests on pattern types.
- Patterns consistent across workspace domain crate. One error type, one ID style.
- Refactor clones when touching file. Boy scout rule for perf.
FAQs
Minimum patterns for new service?
Newtypes for IDs, Result errors, builder for config, Axum state Arc pattern.
When skip typestate?
Linear two-state flows with enum is enough.
patterns in tests?
unwrap OK in tests; production patterns still tested via Result paths.
document pattern ADR?
Yes for typestate and interior mutability choices.
legacy interop?
Anti-corruption layer with TryFrom at FFI/HTTP boundary.
gui patterns?
egui may use interior mut; still minimize RefCell web.
game ECS?
SoA layout pattern over OOP graphs.
cli patterns?
clap parse into newtypes; Result exit codes.
library semver?
Pattern changes affecting public types are breaking.
onboarding?
Read Rust Patterns Basics + Common Anti-Patterns first week.
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+.