rgoussu@goussu: ~/library/rust/toolchain
~/library/rust/toolchain cat cargo-expand.md

cargo-expand — macro expansion

# Prints your code with all macros and derives expanded — the essential debugging view for proc-macro-heavy code, powered by nightly rustc's -Zunpretty.

Conceptsaved 2026-08-09 #rust#tooling#macros#debugging

Overview

cargo expand prints a crate's source after macro expansion — every derive, every attribute macro, every macro_rules! invocation replaced by the code it generates, pretty-printed and syntax-highlighted. In an ecosystem where serde, tokio, sqlx, tonic, axum and half of every dependency tree work by generating code, this is the tool that turns "magic attribute" into "oh, that's all it does" — both for debugging weird errors and for learning how the libraries actually work.

Key points

  • Install once, use forever: cargo install cargo-expand; it drives nightly rustc's -Zunpretty=expanded under the hood, so a nightly toolchain must be installed (the project itself can stay on stable — it invokes cargo +nightly internally).
  • Scope the expansion: cargo expand path::to::module or cargo expand --test integration some_test — full-crate output on a real project is thousands of lines; always narrow to the item you're debugging.
  • The classic uses: seeing what #[derive(Serialize)] does with your #[serde(...)] attributes, what #[tokio::main] wraps around main, why a #[sqlx::test] or #[tracing::instrument] interacts badly with another attribute, and what your own macro_rules! actually produced.
  • Expansion is pre-type-check: expanded output may still not compile — macros can emit code that later phases reject; expand shows what was generated, the compiler error explains why it's wrong.
  • For proc-macro authors the complements are cargo expand on a consumer crate plus trybuild (compile-fail tests) and proc-macro2/syn's cargo expand-friendly output — see Unit testing.
  • rust-analyzer's "Expand macro recursively" covers the quick inline case; cargo-expand remains the tool for whole-module views and pipelines (diffing expansions across versions).

Examples

cargo expand models::user              # one module
cargo expand --lib --features postgres # expansion under a feature set
cargo expand --test api_tests create_user

Related