apollographql

rust-best-practices

5
1
# Install this skill:
npx skills add apollographql/skills --skill "rust-best-practices"

Install specific skill from multi-skill repository

# Description

>

# SKILL.md


name: rust-best-practices
description: >
Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook. Use this skill when:
(1) writing new Rust code or functions,
(2) reviewing or refactoring existing Rust code,
(3) deciding between borrowing vs cloning or ownership patterns,
(4) implementing error handling with Result types,
(5) optimizing Rust code for performance,
(6) writing tests or documentation for Rust projects.
license: MIT
compatibility: Rust 1.70+, Cargo
metadata:
author: apollographql
version: "1.0"
allowed-tools: Bash(cargo:) Bash(rustc:) Bash(rustfmt:) Bash(clippy:) Read Write Edit Glob Grep


Rust Best Practices

Apply these guidelines when writing or reviewing Rust code. Based on Apollo GraphQL's Rust Best Practices Handbook.

Quick Reference

Borrowing & Ownership

  • Prefer &T over .clone() unless ownership transfer is required
  • Use &str over String, &[T] over Vec<T> in function parameters
  • Small Copy types (≤24 bytes) can be passed by value
  • Use Cow<'_, T> when ownership is ambiguous

Error Handling

  • Return Result<T, E> for fallible operations; avoid panic! in production
  • Never use unwrap()/expect() outside tests
  • Use thiserror for library errors, anyhow for binaries only
  • Prefer ? operator over match chains for error propagation

Performance

  • Always benchmark with --release flag
  • Run cargo clippy -- -D clippy::perf for performance hints
  • Avoid cloning in loops; use .iter() instead of .into_iter() for Copy types
  • Prefer iterators over manual loops; avoid intermediate .collect() calls

Linting

Run regularly: cargo clippy --all-targets --all-features --locked -- -D warnings

Key lints to watch:
- redundant_clone - unnecessary cloning
- large_enum_variant - oversized variants (consider boxing)
- needless_collect - premature collection

Use #[expect(clippy::lint)] over #[allow(...)] with justification comment.

Testing

  • Name tests descriptively: process_should_return_error_when_input_empty()
  • One assertion per test when possible
  • Use doc tests (///) for public API examples
  • Consider cargo insta for snapshot testing generated output

Generics & Dispatch

  • Prefer generics (static dispatch) for performance-critical code
  • Use dyn Trait only when heterogeneous collections are needed
  • Box at API boundaries, not internally

Type State Pattern

Encode valid states in the type system to catch invalid operations at compile time:

struct Connection<State> { /* ... */ _state: PhantomData<State> }
struct Disconnected;
struct Connected;

impl Connection<Connected> {
    fn send(&self, data: &[u8]) { /* only connected can send */ }
}

Documentation

  • // comments explain why (safety, workarounds, design rationale)
  • /// doc comments explain what and how for public APIs
  • Every TODO needs a linked issue: // TODO(#42): ...
  • Enable #![deny(missing_docs)] for libraries

Detailed References

For in-depth guidance on specific topics:

  • Coding style & idioms: See references/style.md for borrowing patterns, Option/Result handling, iterator usage, and import organization
  • Error handling: See references/errors.md for thiserror patterns, error hierarchies, and testing errors
  • Performance: See references/performance.md for profiling, memory layout, and iterator optimization
  • Testing: See references/testing.md for test organization, snapshot testing, and assertion strategies
  • Advanced patterns: See references/advanced.md for generics, dispatch, type state, and pointer types

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.