Comprehensive Rust coding guidelines with 179 rules across 14 categories. Use when writing, reviewing, or refactoring Rust code. Covers ownership, error handling, async patterns, API design, memory optimization, performance, testing, and common anti-patterns. Invoke with /rust-skills.
Install
npx skillscat add leonardomso/rust-skills Install via the SkillsCat registry.
SKILL.md
Rust Best Practices
Comprehensive guide for writing high-quality, idiomatic, and highly optimized Rust code. Contains 179 rules across 14 categories, prioritized by impact to guide LLMs in code generation and refactoring.
When to Apply
Reference these guidelines when:
- Writing new Rust functions, structs, or modules
- Implementing error handling or async code
- Designing public APIs for libraries
- Reviewing code for ownership/borrowing issues
- Optimizing memory usage or reducing allocations
- Tuning performance for hot paths
- Refactoring existing Rust code
Rule Categories by Priority
| Priority | Category | Impact | Prefix | Rules |
|---|---|---|---|---|
| 1 | Ownership & Borrowing | CRITICAL | own- |
12 |
| 2 | Error Handling | CRITICAL | err- |
12 |
| 3 | Memory Optimization | CRITICAL | mem- |
15 |
| 4 | API Design | HIGH | api- |
15 |
| 5 | Async/Await | HIGH | async- |
15 |
| 6 | Compiler Optimization | HIGH | opt- |
12 |
| 7 | Naming Conventions | MEDIUM | name- |
16 |
| 8 | Type Safety | MEDIUM | type- |
10 |
| 9 | Testing | MEDIUM | test- |
13 |
| 10 | Documentation | MEDIUM | doc- |
11 |
| 11 | Performance Patterns | MEDIUM | perf- |
11 |
| 12 | Project Structure | LOW | proj- |
11 |
| 13 | Clippy & Linting | LOW | lint- |
11 |
| 14 | Anti-patterns | REFERENCE | anti- |
15 |
Quick Reference
1. Ownership & Borrowing (CRITICAL)
- `own-borrow-over-clone` - Prefer
&Tborrowing over.clone() - `own-slice-over-vec` - Accept
&[T]not&Vec<T>,&strnot&String - `own-cow-conditional` - Use
Cow<'a, T>for conditional ownership - `own-arc-shared` - Use
Arc<T>for thread-safe shared ownership - `own-rc-single-thread` - Use
Rc<T>for single-threaded sharing - `own-refcell-interior` - Use
RefCell<T>for interior mutability (single-thread) - `own-mutex-interior` - Use
Mutex<T>for interior mutability (multi-thread) - `own-rwlock-readers` - Use
RwLock<T>when reads dominate writes - `own-copy-small` - Derive
Copyfor small, trivial types - `own-clone-explicit` - Make
Cloneexplicit, avoid implicit copies - `own-move-large` - Move large data instead of cloning
- `own-lifetime-elision` - Rely on lifetime elision when possible
2. Error Handling (CRITICAL)
- `err-thiserror-lib` - Use
thiserrorfor library error types - `err-anyhow-app` - Use
anyhowfor application error handling - `err-result-over-panic` - Return
Result, don't panic on expected errors - `err-context-chain` - Add context with
.context()or.with_context() - `err-no-unwrap-prod` - Never use
.unwrap()in production code - `err-expect-bugs-only` - Use
.expect()only for programming errors - `err-question-mark` - Use
?operator for clean propagation - `err-from-impl` - Use
#[from]for automatic error conversion - `err-source-chain` - Use
#[source]to chain underlying errors - `err-lowercase-msg` - Error messages: lowercase, no trailing punctuation
- `err-doc-errors` - Document errors with
# Errorssection - `err-custom-type` - Create custom error types, not
Box<dyn Error>
3. Memory Optimization (CRITICAL)
- `mem-with-capacity` - Use
with_capacity()when size is known - `mem-smallvec` - Use
SmallVecfor usually-small collections - `mem-arrayvec` - Use
ArrayVecfor bounded-size collections - `mem-box-large-variant` - Box large enum variants to reduce type size
- `mem-boxed-slice` - Use
Box<[T]>instead ofVec<T>when fixed - `mem-thinvec` - Use
ThinVecfor often-empty vectors - `mem-clone-from` - Use
clone_from()to reuse allocations - `mem-reuse-collections` - Reuse collections with
clear()in loops - `mem-avoid-format` - Avoid
format!()when string literals work - `mem-write-over-format` - Use
write!()instead offormat!() - `mem-arena-allocator` - Use arena allocators for batch allocations
- `mem-zero-copy` - Use zero-copy patterns with slices and
Bytes - `mem-compact-string` - Use
CompactStringfor small string optimization - `mem-smaller-integers` - Use smallest integer type that fits
- `mem-assert-type-size` - Assert hot type sizes to prevent regressions
4. API Design (HIGH)
- `api-builder-pattern` - Use Builder pattern for complex construction
- `api-builder-must-use` - Add
#[must_use]to builder types - `api-newtype-safety` - Use newtypes for type-safe distinctions
- `api-typestate` - Use typestate for compile-time state machines
- `api-sealed-trait` - Seal traits to prevent external implementations
- `api-extension-trait` - Use extension traits to add methods to foreign types
- `api-parse-dont-validate` - Parse into validated types at boundaries
- `api-impl-into` - Accept
impl Into<T>for flexible string inputs - `api-impl-asref` - Accept
impl AsRef<T>for borrowed inputs - `api-must-use` - Add
#[must_use]toResultreturning functions - `api-non-exhaustive` - Use
#[non_exhaustive]for future-proof enums/structs - `api-from-not-into` - Implement
From, notInto(auto-derived) - `api-default-impl` - Implement
Defaultfor sensible defaults - `api-common-traits` - Implement
Debug,Clone,PartialEqeagerly - `api-serde-optional` - Gate
Serialize/Deserializebehind feature flag
5. Async/Await (HIGH)
- `async-tokio-runtime` - Use Tokio for production async runtime
- `async-no-lock-await` - Never hold
Mutex/RwLockacross.await - `async-spawn-blocking` - Use
spawn_blockingfor CPU-intensive work - `async-tokio-fs` - Use
tokio::fsnotstd::fsin async code - `async-cancellation-token` - Use
CancellationTokenfor graceful shutdown - `async-join-parallel` - Use
tokio::join!for parallel operations - `async-try-join` - Use
tokio::try_join!for fallible parallel ops - `async-select-racing` - Use
tokio::select!for racing/timeouts - `async-bounded-channel` - Use bounded channels for backpressure
- `async-mpsc-queue` - Use
mpscfor work queues - `async-broadcast-pubsub` - Use
broadcastfor pub/sub patterns - `async-watch-latest` - Use
watchfor latest-value sharing - `async-oneshot-response` - Use
oneshotfor request/response - `async-joinset-structured` - Use
JoinSetfor dynamic task groups - `async-clone-before-await` - Clone data before await, release locks
6. Compiler Optimization (HIGH)
- `opt-inline-small` - Use
#[inline]for small hot functions - `opt-inline-always-rare` - Use
#[inline(always)]sparingly - `opt-inline-never-cold` - Use
#[inline(never)]for cold paths - `opt-cold-unlikely` - Use
#[cold]for error/unlikely paths - `opt-likely-hint` - Use
likely()/unlikely()for branch hints - `opt-lto-release` - Enable LTO in release builds
- `opt-codegen-units` - Use
codegen-units = 1for max optimization - `opt-pgo-profile` - Use PGO for production builds
- `opt-target-cpu` - Set
target-cpu=nativefor local builds - `opt-bounds-check` - Use iterators to avoid bounds checks
- `opt-simd-portable` - Use portable SIMD for data-parallel ops
- `opt-cache-friendly` - Design cache-friendly data layouts (SoA)
7. Naming Conventions (MEDIUM)
- `name-types-camel` - Use
UpperCamelCasefor types, traits, enums - `name-variants-camel` - Use
UpperCamelCasefor enum variants - `name-funcs-snake` - Use
snake_casefor functions, methods, modules - `name-consts-screaming` - Use
SCREAMING_SNAKE_CASEfor constants/statics - `name-lifetime-short` - Use short lowercase lifetimes:
'a,'de,'src - `name-type-param-single` - Use single uppercase for type params:
T,E,K,V - `name-as-free` -
as_prefix: free reference conversion - `name-to-expensive` -
to_prefix: expensive conversion - `name-into-ownership` -
into_prefix: ownership transfer - `name-no-get-prefix` - No
get_prefix for simple getters - `name-is-has-bool` - Use
is_,has_,can_for boolean methods - `name-iter-convention` - Use
iter/iter_mut/into_iterfor iterators - `name-iter-method` - Name iterator methods consistently
- `name-iter-type-match` - Iterator type names match method
- `name-acronym-word` - Treat acronyms as words:
UuidnotUUID - `name-crate-no-rs` - Crate names: no
-rssuffix
8. Type Safety (MEDIUM)
- `type-newtype-ids` - Wrap IDs in newtypes:
UserId(u64) - `type-newtype-validated` - Newtypes for validated data:
Email,Url - `type-enum-states` - Use enums for mutually exclusive states
- `type-option-nullable` - Use
Option<T>for nullable values - `type-result-fallible` - Use
Result<T, E>for fallible operations - `type-phantom-marker` - Use
PhantomData<T>for type-level markers - `type-never-diverge` - Use
!type for functions that never return - `type-generic-bounds` - Add trait bounds only where needed
- `type-no-stringly` - Avoid stringly-typed APIs, use enums/newtypes
- `type-repr-transparent` - Use
#[repr(transparent)]for FFI newtypes
9. Testing (MEDIUM)
- `test-cfg-test-module` - Use
#[cfg(test)] mod tests { } - `test-use-super` - Use
use super::*;in test modules - `test-integration-dir` - Put integration tests in
tests/directory - `test-descriptive-names` - Use descriptive test names
- `test-arrange-act-assert` - Structure tests as arrange/act/assert
- `test-proptest-properties` - Use
proptestfor property-based testing - `test-mockall-mocking` - Use
mockallfor trait mocking - `test-mock-traits` - Use traits for dependencies to enable mocking
- `test-fixture-raii` - Use RAII pattern (Drop) for test cleanup
- `test-tokio-async` - Use
#[tokio::test]for async tests - `test-should-panic` - Use
#[should_panic]for panic tests - `test-criterion-bench` - Use
criterionfor benchmarking - `test-doctest-examples` - Keep doc examples as executable tests
10. Documentation (MEDIUM)
- `doc-all-public` - Document all public items with
/// - `doc-module-inner` - Use
//!for module-level documentation - `doc-examples-section` - Include
# Exampleswith runnable code - `doc-errors-section` - Include
# Errorsfor fallible functions - `doc-panics-section` - Include
# Panicsfor panicking functions - `doc-safety-section` - Include
# Safetyfor unsafe functions - `doc-question-mark` - Use
?in examples, not.unwrap() - `doc-hidden-setup` - Use
#prefix to hide example setup code - `doc-intra-links` - Use intra-doc links:
[Vec] - `doc-link-types` - Link related types and functions in docs
- `doc-cargo-metadata` - Fill
Cargo.tomlmetadata
11. Performance Patterns (MEDIUM)
- `perf-iter-over-index` - Prefer iterators over manual indexing
- `perf-iter-lazy` - Keep iterators lazy, collect() only when needed
- `perf-collect-once` - Don't
collect()intermediate iterators - `perf-entry-api` - Use
entry()API for map insert-or-update - `perf-drain-reuse` - Use
drain()to reuse allocations - `perf-extend-batch` - Use
extend()for batch insertions - `perf-chain-avoid` - Avoid
chain()in hot loops - `perf-collect-into` - Use
collect_into()for reusing containers - `perf-black-box-bench` - Use
black_box()in benchmarks - `perf-release-profile` - Optimize release profile settings
- `perf-profile-first` - Profile before optimizing
12. Project Structure (LOW)
- `proj-lib-main-split` - Keep
main.rsminimal, logic inlib.rs - `proj-mod-by-feature` - Organize modules by feature, not type
- `proj-flat-small` - Keep small projects flat
- `proj-mod-rs-dir` - Use
mod.rsfor multi-file modules - `proj-pub-crate-internal` - Use
pub(crate)for internal APIs - `proj-pub-super-parent` - Use
pub(super)for parent-only visibility - `proj-pub-use-reexport` - Use
pub usefor clean public API - `proj-prelude-module` - Create
preludemodule for common imports - `proj-bin-dir` - Put multiple binaries in
src/bin/ - `proj-workspace-large` - Use workspaces for large projects
- `proj-workspace-deps` - Use workspace dependency inheritance
13. Clippy & Linting (LOW)
- `lint-deny-correctness` -
#![deny(clippy::correctness)] - `lint-warn-suspicious` -
#![warn(clippy::suspicious)] - `lint-warn-style` -
#![warn(clippy::style)] - `lint-warn-complexity` -
#![warn(clippy::complexity)] - `lint-warn-perf` -
#![warn(clippy::perf)] - `lint-pedantic-selective` - Enable
clippy::pedanticselectively - `lint-missing-docs` -
#![warn(missing_docs)] - `lint-unsafe-doc` -
#![warn(clippy::undocumented_unsafe_blocks)] - `lint-cargo-metadata` -
#![warn(clippy::cargo)]for published crates - `lint-rustfmt-check` - Run
cargo fmt --checkin CI - `lint-workspace-lints` - Configure lints at workspace level
14. Anti-patterns (REFERENCE)
- `anti-unwrap-abuse` - Don't use
.unwrap()in production code - `anti-expect-lazy` - Don't use
.expect()for recoverable errors - `anti-clone-excessive` - Don't clone when borrowing works
- `anti-lock-across-await` - Don't hold locks across
.await - `anti-string-for-str` - Don't accept
&Stringwhen&strworks - `anti-vec-for-slice` - Don't accept
&Vec<T>when&[T]works - `anti-index-over-iter` - Don't use indexing when iterators work
- `anti-panic-expected` - Don't panic on expected/recoverable errors
- `anti-empty-catch` - Don't use empty
if let Err(_) = ...blocks - `anti-over-abstraction` - Don't over-abstract with excessive generics
- `anti-premature-optimize` - Don't optimize before profiling
- `anti-type-erasure` - Don't use
Box<dyn Trait>whenimpl Traitworks - `anti-format-hot-path` - Don't use
format!()in hot paths - `anti-collect-intermediate` - Don't
collect()intermediate iterators - `anti-stringly-typed` - Don't use strings for structured data
Recommended Cargo.toml Settings
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true
[profile.bench]
inherits = "release"
debug = true
strip = false
[profile.dev]
opt-level = 0
debug = true
[profile.dev.package."*"]
opt-level = 3 # Optimize dependencies in devHow to Use
This skill provides rule identifiers for quick reference. When generating or reviewing Rust code:
- Check relevant category based on task type
- Apply rules with matching prefix
- Prioritize CRITICAL > HIGH > MEDIUM > LOW
- Read rule files in
rules/for detailed examples
Rule Application by Task
| Task | Primary Categories |
|---|---|
| New function | own-, err-, name- |
| New struct/API | api-, type-, doc- |
| Async code | async-, own- |
| Error handling | err-, api- |
| Memory optimization | mem-, own-, perf- |
| Performance tuning | opt-, mem-, perf- |
| Code review | anti-, lint- |
Sources
This skill synthesizes best practices from:
- Rust API Guidelines
- Rust Performance Book
- Rust Design Patterns
- Production codebases: ripgrep, tokio, serde, polars, axum, deno
- Clippy lint documentation
- Community conventions (2024-2025)