Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
leonardomso avatar

Rust Skills

  • 3.6k installs
  • 367 repo stars
  • Updated June 14, 2026
  • leonardomso/rust-skills

rust-skills is a comprehensive Rust coding guideline skill with 265 prioritized rules across 26 categories.

About

Rust Skills is a comprehensive guideline set with 265 rules across 26 categories prioritized by impact for Rust 1.96 and the 2024 edition. Critical tiers cover ownership and borrowing, error handling with thiserror and anyhow patterns, memory optimization including SmallVec and zero-copy slices, and unsafe code safety comments with Miri CI guidance. High-priority sections span API design, async await, concurrency, compiler optimization, and numeric safety. Medium tiers address type safety, traits, serde, pattern matching, macros, closures, collections, naming, testing, documentation, observability, and performance patterns. Each rule links to a dedicated markdown file such as own-borrow-over-clone and err-no-unwrap-prod. The skill targets new modules, public API design, hot path tuning, and code review for borrowing and allocation issues. Sources include Rust API Guidelines, Performance Book, Rustonomicon, and production codebases like tokio, serde, and axum.

  • 265 rules across 26 categories with impact priority.
  • Critical ownership, error, memory, and unsafe sections first.
  • Linked rule files such as own-borrow-over-clone and err-no-unwrap-prod.
  • Async, concurrency, and API design high-priority guidance.
  • Current for Rust 1.96 and 2024 edition patterns.

Rust Skills by the numbers

  • 3,611 all-time installs (skills.sh)
  • +689 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Ranked #6 of 129 Rust skills by installs in the Skillselion catalog
  • Security screen: MEDIUM risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

rust-skills capabilities & compatibility

Capabilities
ownership and borrowing rule catalog · error handling with result and custom types · memory and allocation optimization patterns · unsafe code safety and miri guidance · async await and concurrency best practices · api design and documentation conventions
Use cases
code review · refactoring · api development
Pricing
Free
From the docs

What rust-skills says it does

Contains 265 rules across 26 categories, prioritized by impact
SKILL.md
npx skills add https://github.com/leonardomso/rust-skills --skill rust-skills

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs3.6k
repo stars367
Security audit3 / 3 scanners passed
Last updatedJune 14, 2026
Repositoryleonardomso/rust-skills

What idiomatic Rust patterns should I follow for ownership, errors, async, and performance?

Apply 265 prioritized Rust rules across ownership, errors, async, unsafe, API design, and performance when writing or reviewing code.

Who is it for?

Rust developers writing, reviewing, or refactoring production Rust modules and public APIs.

Skip if: Skip for non-Rust languages, beginner syntax tutorials, or cargo install help only.

When should I use this skill?

User writes Rust code, reviews borrowing, async, unsafe, serde, or performance hot paths.

What you get

Code aligned to prioritized rust-skills rules for the relevant category and hot paths.

  • Idiomatic Rust code
  • Review guidance

By the numbers

  • Contains 179 rules across 14 categories
  • Version 1.0.0 under MIT license

Files

SKILL.mdMarkdownGitHub ↗

Rust Best Practices

Comprehensive guide for writing high-quality, idiomatic, and highly optimized Rust code. Contains 265 rules across 26 categories, prioritized by impact to guide LLMs in code generation and refactoring. Current for Rust 1.96 (2024 edition).

When to Apply

Reference these guidelines when:

  • Writing new Rust functions, structs, or modules
  • Implementing error handling or async code
  • Writing concurrent, parallel, or unsafe 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

PriorityCategoryImpactPrefixRules
1Ownership & BorrowingCRITICALown-12
2Error HandlingCRITICALerr-12
3Memory OptimizationCRITICALmem-17
4Unsafe CodeCRITICALunsafe-7
5API DesignHIGHapi-17
6Async/AwaitHIGHasync-18
7ConcurrencyHIGHconc-4
8Compiler OptimizationHIGHopt-12
9Numeric & Arithmetic SafetyHIGHnum-5
10Type SafetyMEDIUMtype-13
11Trait & Generics DesignMEDIUMtrait-6
12ConversionsMEDIUMconv-3
13Const & Compile-TimeMEDIUMconst-4
14SerdeMEDIUMserde-8
15Pattern MatchingMEDIUMpat-5
16MacrosMEDIUMmacro-8
17ClosuresMEDIUMclosure-5
18CollectionsMEDIUMcoll-4
19Naming ConventionsMEDIUMname-16
20TestingMEDIUMtest-15
21DocumentationMEDIUMdoc-12
22ObservabilityMEDIUMobs-7
23Performance PatternsMEDIUMperf-13
24Project StructureLOWproj-14
25Clippy & LintingLOWlint-13
26Anti-patternsREFERENCEanti-15

---

Quick Reference

1. Ownership & Borrowing (CRITICAL)

  • `own-borrow-over-clone` - Prefer &T borrowing over .clone()
  • `own-slice-over-vec` - Accept &[T] not &Vec<T>, &str not &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 shared ownership in single-threaded contexts
  • `own-refcell-interior` - Use RefCell<T> for interior mutability in single-threaded code
  • `own-mutex-interior` - Use Mutex<T> for interior mutability across threads
  • `own-rwlock-readers` - Use RwLock<T> when reads significantly outnumber writes
  • `own-copy-small` - Implement Copy for small, simple types
  • `own-clone-explicit` - Use explicit Clone for types where copying has meaningful cost
  • `own-move-large` - Move large types instead of copying; use Box if moves are expensive
  • `own-lifetime-elision` - Rely on lifetime elision rules; add explicit lifetimes only when required

2. Error Handling (CRITICAL)

  • `err-thiserror-lib` - Use thiserror for library error types
  • `err-anyhow-app` - Use anyhow for application error handling
  • `err-result-over-panic` - Return Result<T, E> instead of panicking for recoverable errors
  • `err-context-chain` - Add context with .context() or .with_context()
  • `err-no-unwrap-prod` - Avoid unwrap() in production code; use ?, expect(), or handle errors
  • `err-expect-bugs-only` - Use expect() only for invariants that indicate bugs, not user errors
  • `err-question-mark` - Use ? operator for clean propagation
  • `err-from-impl` - Implement From<E> for error conversions to enable ? operator
  • `err-source-chain` - Preserve error chains with #[source] or source() method
  • `err-lowercase-msg` - Start error messages lowercase, no trailing punctuation
  • `err-doc-errors` - Document error conditions with # Errors section in doc comments
  • `err-custom-type` - Define custom error types for domain-specific failures

3. Memory Optimization (CRITICAL)

  • `mem-with-capacity` - Use with_capacity() when size is known
  • `mem-smallvec` - Use SmallVec for usually-small collections
  • `mem-arrayvec` - Use ArrayVec<T, N> for fixed-capacity collections that never heap-allocate
  • `mem-box-large-variant` - Box large enum variants to reduce overall enum size
  • `mem-boxed-slice` - Use Box<[T]> instead of Vec<T> for fixed-size heap data
  • `mem-thinvec` - Use ThinVec<T> for nullable collections with minimal overhead
  • `mem-clone-from` - Use clone_from() to reuse allocations when repeatedly cloning
  • `mem-reuse-collections` - Clear and reuse collections instead of creating new ones in loops
  • `mem-avoid-format` - Avoid format!() when string literals work
  • `mem-write-over-format` - Use write!() into existing buffers instead of format!() allocations
  • `mem-arena-allocator` - Use arena allocators for batch allocations
  • `mem-zero-copy` - Use zero-copy patterns with slices and Bytes
  • `mem-compact-string` - Use compact string types for memory-constrained string storage
  • `mem-smaller-integers` - Use appropriately-sized integers to reduce memory footprint
  • `mem-assert-type-size` - Use static assertions to guard against accidental type size growth
  • `mem-take-replace` - Use mem::take / mem::replace to move a value out of a &mut without cloning
  • `mem-drop-order` - Know and control drop order: struct fields drop top-to-bottom, locals in reverse

4. Unsafe Code (CRITICAL)

  • `unsafe-safety-comment` - Write a // SAFETY: comment above every unsafe block and a # Safety section in every unsafe fn.
  • `unsafe-minimize-scope` - Keep unsafe blocks as small as possible — mark only the operation that requires unsafety, not the surrounding safe code.
  • `unsafe-miri-ci` - Run cargo miri test in CI for every crate that contains unsafe code.
  • `unsafe-maybeuninit` - Use MaybeUninit<T> for uninitialized memory; never use mem::uninitialized() or mem::zeroed() for types with validity invariants.
  • `unsafe-extern-block` - In Rust 2024, wrap extern blocks in unsafe extern { } and annotate each item as safe or unsafe.
  • `unsafe-send-sync-manual` - Document the invariants when manually implementing Send or Sync; prefer letting the compiler derive them automatically.
  • `unsafe-no-mangle-unsafe` - In Rust 2024, write #[unsafe(no_mangle)], #[unsafe(export_name = "...")], and #[unsafe(link_section = "...")] — not the bare attribute forms.

5. API Design (HIGH)

  • `api-builder-pattern` - Use Builder pattern for complex construction
  • `api-builder-must-use` - Mark builder methods with #[must_use] to prevent silent drops
  • `api-newtype-safety` - Use newtypes to prevent mixing semantically different values
  • `api-typestate` - Use typestate pattern to encode state machine invariants in the type system
  • `api-sealed-trait` - Use sealed traits to prevent external implementations while allowing use
  • `api-extension-trait` - Use extension traits to add methods to external types
  • `api-parse-dont-validate` - Parse into validated types at boundaries
  • `api-impl-into` - Accept impl Into<T> for flexible APIs, implement From<T> for conversions
  • `api-impl-asref` - Use AsRef<T> when you only need to borrow the inner data
  • `api-must-use` - Mark types and functions with #[must_use] when ignoring results is likely a bug
  • `api-non-exhaustive` - Use #[non_exhaustive] on public enums and structs for forward compatibility
  • `api-from-not-into` - Implement From<T>, not Into<U> - From gives you Into for free
  • `api-default-impl` - Implement Default for types with sensible default values
  • `api-common-traits` - Implement standard traits (Debug, Clone, PartialEq, etc.) for public types
  • `api-serde-optional` - Make serde a feature flag, not a hard dependency for library crates
  • `api-impl-fromiterator` - Implement FromIterator and Extend for collection types, and IntoIterator for all three reference forms
  • `api-operator-overload` - Overload operators only when the semantics are natural and unsurprising

6. Async/Await (HIGH)

  • `async-tokio-runtime` - Configure Tokio runtime appropriately for your workload
  • `async-no-lock-await` - Never hold Mutex/RwLock across .await
  • `async-spawn-blocking` - Use spawn_blocking for CPU-intensive work
  • `async-tokio-fs` - Use tokio::fs instead of std::fs in async code
  • `async-cancellation-token` - Use CancellationToken for graceful shutdown and task cancellation
  • `async-join-parallel` - Use join! or try_join! for concurrent independent futures
  • `async-try-join` - Use try_join! for concurrent fallible operations with early return on error
  • `async-select-racing` - Use select! to race futures and handle the first to complete
  • `async-bounded-channel` - Use bounded channels to apply backpressure and prevent unbounded memory growth
  • `async-mpsc-queue` - Use mpsc channels for async message queues between tasks
  • `async-broadcast-pubsub` - Use broadcast channel for pub/sub where all subscribers receive all messages
  • `async-watch-latest` - Use watch channel for sharing the latest value with multiple observers
  • `async-oneshot-response` - Use oneshot channel for request-response patterns
  • `async-joinset-structured` - Use JoinSet for managing dynamic collections of spawned tasks
  • `async-clone-before-await` - Clone Arc/Rc data before await points to avoid holding references across suspension
  • `async-fn-in-trait` - Use native async fn in traits (stable 1.75) instead of the async_trait macro
  • `async-async-fn-bounds` - Use AsyncFn/AsyncFnMut/AsyncFnOnce bounds instead of F: Fn() -> Fut, Fut: Future
  • `async-cancel-safety` - Ensure futures used in tokio::select! branches are cancellation-safe

7. Concurrency (HIGH)

  • `conc-rayon-par-iter` - Use rayon's par_iter() for CPU-bound data parallelism
  • `conc-scoped-threads` - Use std::thread::scope to borrow stack data across threads
  • `conc-atomic-ordering` - Use the weakest correct memory Ordering for every atomic operation
  • `conc-thread-local` - Prefer thread_local! with Cell/RefCell over static mut

8. Compiler Optimization (HIGH)

  • `opt-inline-small` - Use #[inline] for small hot functions
  • `opt-inline-always-rare` - Use #[inline(always)] sparingly—only for critical hot paths proven by profiling
  • `opt-inline-never-cold` - Use #[inline(never)] and #[cold] for error paths and rarely-executed code
  • `opt-cold-unlikely` - Mark unlikely code paths with #[cold] to help compiler optimization
  • `opt-likely-hint` - Use code structure to hint at likely branches; use intrinsics on nightly
  • `opt-lto-release` - Enable LTO in release builds
  • `opt-codegen-units` - Set codegen-units = 1 for maximum optimization in release builds
  • `opt-pgo-profile` - Use Profile-Guided Optimization (PGO) for maximum performance
  • `opt-target-cpu` - Use target-cpu=native for maximum performance on known deployment targets
  • `opt-bounds-check` - Use iterators and patterns that eliminate bounds checks in hot paths
  • `opt-simd-portable` - Use portable SIMD for vectorized operations across architectures
  • `opt-cache-friendly` - Organize data for cache-efficient access patterns

9. Numeric & Arithmetic Safety (HIGH)

  • `num-overflow-explicit` - Handle integer overflow explicitly: checked_/saturating_/wrapping_/overflowing_
  • `num-cast-try-from` - Avoid as for narrowing casts; use From for widening and TryFrom for narrowing
  • `num-float-compare` - Don't compare floats with ==; use a tolerance, and total_cmp for ordering
  • `num-saturating-clamp` - Bound values with clamp and saturating arithmetic
  • `num-nonzero` - Use NonZero* types to forbid zero and unlock the niche optimization

10. Type Safety (MEDIUM)

  • `type-newtype-ids` - Wrap IDs in newtypes: UserId(u64)
  • `type-newtype-validated` - Use newtypes to enforce validation at construction time
  • `type-enum-states` - Use enums for mutually exclusive states
  • `type-option-nullable` - Use Option<T> for values that might not exist
  • `type-result-fallible` - Use Result<T, E> for operations that can fail
  • `type-phantom-marker` - Use PhantomData to express type relationships without runtime cost
  • `type-never-diverge` - Use ! (never type) for functions that never return
  • `type-generic-bounds` - Add trait bounds only where needed, prefer where clauses for readability
  • `type-no-stringly` - Avoid stringly-typed APIs; use enums, newtypes, or validated types
  • `type-repr-transparent` - Use #[repr(transparent)] for newtypes in FFI contexts
  • `type-deref-coercion` - Implement Deref/DerefMut only for smart-pointer and transparent wrapper types
  • `type-display-vs-debug` - Use Display for user-facing output and Debug for diagnostics; never swap them
  • `type-numeric-fmt` - Implement LowerHex, UpperHex, Octal, and Binary for numeric newtypes

11. Trait & Generics Design (MEDIUM)

  • `trait-associated-type-vs-generic` - Use an associated type when each impl has exactly one output type; use a generic parameter when a type can implement the trait for many input types
  • `trait-blanket-impl` - Use a blanket impl impl<T: Bound> Trait for T to give behaviour to every type that satisfies a bound
  • `trait-coherence-newtype` - Respect the orphan rule; wrap a foreign type in a newtype to implement a foreign trait on it
  • `trait-default-methods` - Define a trait in terms of a few required methods plus defaulted ones built on top of them
  • `trait-dyn-vs-generic` - Choose static dispatch (generics / impl Trait) vs dynamic dispatch (dyn Trait) deliberately
  • `trait-object-safety` - Keep a trait dyn-compatible (object-safe) when you need dyn Trait

12. Conversions (MEDIUM)

  • `conv-tryfrom-fallible` - Implement TryFrom for fallible conversions instead of ad-hoc conversion functions
  • `conv-fromstr-parsing` - Implement FromStr to enable str::parse for string-to-type conversions
  • `conv-asmut-mutable` - Accept impl AsMut<T> for flexible mutable borrowed inputs instead of concrete mutable references

13. Const & Compile-Time (MEDIUM)

  • `const-block` - Use inline const { } blocks for compile-time evaluation and assertions
  • `const-fn` - Make functions const fn when they can run at compile time
  • `const-generics` - Parameterize over values with const generics <const N: usize>
  • `const-vs-static` - Use const for an inlined value and static for a single addressed instance

14. Serde (MEDIUM)

  • `serde-rename-all` - Match the external naming convention with #[serde(rename_all = ...)]
  • `serde-default-compat` - Use #[serde(default)] for optional and backward-compatible fields
  • `serde-skip-empty` - Omit empty fields with skip_serializing_if
  • `serde-flatten` - Inline nested structs or capture extra keys with #[serde(flatten)]
  • `serde-enum-representation` - Choose enum tagging deliberately: externally, internally, adjacently tagged, or untagged
  • `serde-deny-unknown-fields` - Reject unexpected keys with #[serde(deny_unknown_fields)]
  • `serde-custom-with` - Customize a field's (de)serialization with with / serialize_with / deserialize_with
  • `serde-try-from-validate` - Validate while deserializing with #[serde(try_from = "Raw")]

15. Pattern Matching (MEDIUM)

  • `pat-let-else` - Use let ... else for early-return pattern extraction
  • `pat-matches-macro` - Use matches!() for boolean pattern tests
  • `pat-if-let-chains` - Use if let chains to combine pattern bindings and conditions
  • `pat-exhaustive-enum` - Match owned enums exhaustively; avoid catch-all _ that hides new variants
  • `pat-at-bindings` - Use @ bindings to capture a value while matching it against a pattern

16. Macros (MEDIUM)

  • `macro-prefer-functions` - Reach for a macro only when a function or generic cannot express it
  • `macro-rules-hygiene` - Rely on macro_rules! hygiene and use $crate for paths to your crate's items
  • `macro-fragment-specifiers` - Capture with precise fragment specifiers, not raw :tt, where you can
  • `macro-export-crate-path` - Export declarative macros with #[macro_export] and a clean import path
  • `macro-private-helpers` - Hide macro-generated helper items behind a #[doc(hidden)] pub mod __private
  • `macro-proc-two-crate` - Put procedural macros in a dedicated proc-macro = true crate and re-export from the facade
  • `macro-proc-syn-quote` - Build procedural macros with syn, quote, and proc-macro2
  • `macro-proc-error-spans` - Report proc-macro errors as spanned compile errors, never by panicking

17. Closures (MEDIUM)

  • `closure-fn-trait-bounds` - Require the least restrictive Fn trait a callback needs (FnOnceFnMutFn)
  • `closure-impl-fn-return` - Return closures as impl Fn/FnMut/FnOnce, not Box<dyn Fn>
  • `closure-move-capture` - Use move for closures that outlive the current scope; clone before move to keep the original
  • `closure-static-vs-dyn` - Accept impl Fn (generic) for hot callbacks; use &dyn Fn/Box<dyn Fn> to cut code size or to store them
  • `closure-disjoint-capture` - Capture only what you use; lean on edition-2021 disjoint closure captures

18. Collections (MEDIUM)

  • `coll-binaryheap` - Use BinaryHeap for a priority queue or repeated max-extraction
  • `coll-map-choice` - Pick the map by access pattern: HashMap (fast, unordered), BTreeMap (sorted / range queries), IndexMap (insertion order)
  • `coll-seq-choice` - Default to Vec; use VecDeque for queue/deque behaviour; avoid LinkedList
  • `coll-set-membership` - Use HashSet/BTreeSet for membership tests and dedup, not linear Vec::contains

19. Naming Conventions (MEDIUM)

  • `name-types-camel` - Use UpperCamelCase for types, traits, and enum names
  • `name-variants-camel` - Use UpperCamelCase for enum variants
  • `name-funcs-snake` - Use snake_case for functions, methods, variables, and modules
  • `name-consts-screaming` - Use SCREAMING_SNAKE_CASE for constants and statics
  • `name-lifetime-short` - Use short, conventional lifetime names: 'a, 'b, 'de, 'src
  • `name-type-param-single` - Use single uppercase letters for type parameters: T, E, K, V
  • `name-as-free` - as_ prefix: free reference conversion
  • `name-to-expensive` - Use to_ prefix for expensive conversions that allocate or compute
  • `name-into-ownership` - Use into_ prefix for ownership-consuming conversions
  • `name-no-get-prefix` - Omit get_ prefix for simple getters
  • `name-is-has-bool` - Use is_, has_, can_, should_ prefixes for boolean-returning methods
  • `name-iter-convention` - Use iter/iter_mut/into_iter for iterator methods
  • `name-iter-method` - Name iterator methods iter(), iter_mut(), and into_iter() consistently
  • `name-iter-type-match` - Name iterator types after their source method
  • `name-acronym-word` - Treat acronyms as words in identifiers: HttpServer, not HTTPServer
  • `name-crate-no-rs` - Don't suffix crate names with -rs or -rust

20. Testing (MEDIUM)

  • `test-cfg-test-module` - Put unit tests in #[cfg(test)] mod tests { } within each module
  • `test-use-super` - Use use super::*; in test modules to access parent module items
  • `test-integration-dir` - Put integration tests in the tests/ directory
  • `test-descriptive-names` - Use descriptive test names that explain what is being tested
  • `test-arrange-act-assert` - Structure tests with clear Arrange, Act, Assert sections
  • `test-proptest-properties` - Use proptest for property-based testing
  • `test-mockall-mocking` - Use mockall for trait mocking
  • `test-mock-traits` - Use traits for dependencies to enable mocking in tests
  • `test-fixture-raii` - Use RAII pattern (Drop trait) for automatic test cleanup
  • `test-tokio-async` - Use #[tokio::test] for async tests
  • `test-should-panic` - Use #[should_panic] to test that code panics as expected
  • `test-criterion-bench` - Use criterion for benchmarking
  • `test-doctest-examples` - Keep documentation examples as executable doctests
  • `test-loom-concurrency` - Use loom to exhaustively test lock-free and concurrent code
  • `test-snapshot-testing` - Use snapshot testing (insta) for complex or serialized output

21. Documentation (MEDIUM)

  • `doc-all-public` - Document all public items with /// doc comments
  • `doc-module-inner` - Use //! for module-level documentation
  • `doc-examples-section` - Include # Examples with runnable code
  • `doc-errors-section` - Include # Errors section for fallible functions
  • `doc-panics-section` - Include # Panics section for functions that can panic
  • `doc-safety-section` - Include # Safety section for 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 to reference types and items
  • `doc-link-types` - Use intra-doc links to connect related types and functions
  • `doc-cargo-metadata` - Fill Cargo.toml metadata for published crates
  • `doc-crate-readme` - Unify the README and crate root docs with #![doc = include_str!("../README.md")]

22. Observability (MEDIUM)

  • `obs-tracing-over-log` - Use tracing for structured, span-aware diagnostics instead of println! or bare log
  • `obs-library-facade` - Libraries emit through the tracing/log facade and never install a subscriber
  • `obs-structured-fields` - Record structured key-value fields, not values interpolated into the message string
  • `obs-instrument-spans` - Use #[tracing::instrument] and spans to attach context to async tasks and requests
  • `obs-levels-filter` - Use log levels meaningfully and filter with EnvFilter / RUST_LOG
  • `obs-error-chain` - Log errors with their full source chain, and log each error exactly once
  • `obs-no-sensitive-data` - Never log secrets or PII; redact or skip them

23. 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
  • `perf-ahash` - Use a faster hasher (ahash / FxHashMap) when DoS resistance is not needed
  • `perf-io-buffering` - Wrap Read/Write in BufReader/BufWriter for many small operations

24. Project Structure (LOW)

  • `proj-lib-main-split` - Keep main.rs minimal, logic in lib.rs
  • `proj-mod-by-feature` - Organize modules by feature, not type
  • `proj-flat-small` - Keep small projects flat
  • `proj-mod-rs-dir` - Use mod.rs for 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 use for clean public API
  • `proj-prelude-module` - Create prelude module 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 for consistent versions across crates
  • `proj-feature-additive` - Design Cargo features to be strictly additive
  • `proj-msrv-declare` - Declare rust-version (MSRV) in Cargo.toml and test it in CI
  • `proj-build-rs-minimal` - Keep build.rs minimal, deterministic, and idempotent

25. Clippy & Linting (LOW)

  • `lint-deny-correctness` - #![deny(clippy::correctness)]
  • `lint-warn-suspicious` - Enable clippy::suspicious for likely bugs
  • `lint-warn-style` - Enable clippy::style for idiomatic code
  • `lint-warn-complexity` - Enable clippy::complexity for simpler code
  • `lint-warn-perf` - Enable clippy::perf for performance improvements
  • `lint-pedantic-selective` - Enable clippy::pedantic selectively
  • `lint-missing-docs` - Warn on missing documentation for public items
  • `lint-unsafe-doc` - Require documentation for unsafe blocks
  • `lint-cargo-metadata` - Enable clippy::cargo for published crates
  • `lint-rustfmt-check` - Run cargo fmt --check in CI
  • `lint-workspace-lints` - Configure lints at workspace level for consistent enforcement
  • `lint-cfg-check` - Enable unexpected_cfgs and declare known cfgs to catch feature-gate typos
  • `lint-clippy-nursery-selected` - Enable high-value clippy::nursery lints selectively, not the whole group

26. 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 points
  • `anti-string-for-str` - Don't accept &String when &str works
  • `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 or recoverable errors
  • `anti-empty-catch` - Don't silently ignore errors
  • `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> when impl Trait works
  • `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 where enums or newtypes would provide type safety

---

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 dev

---

How to Use

This skill provides rule identifiers for quick reference. When generating or reviewing Rust code:

1. Check relevant category based on task type 2. Apply rules with matching prefix 3. Prioritize CRITICAL > HIGH > MEDIUM > LOW 4. Read rule files in rules/ for detailed examples

Rule Application by Task

TaskPrimary Categories
New functionown-, err-, name-, pat-
New struct/APIapi-, type-, conv-, doc-
Async codeasync-, own-
Concurrency / parallelismconc-, async-, own-
Unsafe codeunsafe-, type-, test-
Error handlingerr-, api-, pat-
Type conversionsconv-, api-
Serialization (serde)serde-, type-, api-
Numeric / arithmeticnum-, type-
Macros / code generationmacro-, anti-
Closures / callbacksclosure-, type-
Logging / observabilityobs-, err-
Memory optimizationmem-, own-, perf-
Performance tuningopt-, mem-, perf-
Code reviewanti-, lint-

---

Sources & Attribution

This skill is an independent synthesis of official Rust guidance, well-known books, and patterns from widely-used crates. It is not affiliated with or endorsed by the Rust project or any crate author; the text and code examples are original.

Official Rust documentation

Books & guides

Tooling

Real-world codebases studied for idioms

  • ripgrep, tokio, serde, clap, polars, axum, cargo, hyper, bevy, rayon, and dtolnay's crates (thiserror, anyhow, syn)

This project is MIT-licensed. Referenced upstream materials remain under their own licenses (the official Rust docs and API Guidelines are dual MIT / Apache-2.0).

Related skills

How it compares

Use rust-skills for comprehensive 179-rule Rust idioms during generation and review; narrower Rust skills suit single-topic fixes like clippy lints only.

FAQ

How are rules organized?

Twenty-six categories sorted by impact from ownership and errors through anti-patterns.

Library versus app errors?

Use thiserror for libraries and anyhow for application error handling per err rules.

When add explicit lifetimes?

Rely on elision first; add lifetimes only when the compiler requires them.

Is Rust Skills safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Rustbackend

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.