From 7c7a03927af82ccd4c7d71a1603b7e4ec094ea58 Mon Sep 17 00:00:00 2001 From: kaze Date: Tue, 24 Mar 2026 10:13:40 +0100 Subject: [PATCH] docs: consolidate state management docs in crate root (#3683) Co-authored-by: Yann Simon --- axum-core/src/extract/from_ref.rs | 3 +- axum/src/docs/routing/with_state.md | 7 +++++ axum/src/extract/state.rs | 5 +++ axum/src/lib.rs | 47 +++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/axum-core/src/extract/from_ref.rs b/axum-core/src/extract/from_ref.rs index d38d121c..cda952af 100644 --- a/axum-core/src/extract/from_ref.rs +++ b/axum-core/src/extract/from_ref.rs @@ -1,13 +1,14 @@ /// Used to do reference-to-value conversions thus not consuming the input value. /// /// This is mainly used with [`State`] to extract "substates" from a reference to main application -/// state. +/// state. See ["Sharing state with handlers"][sharing-state] for a worked example. /// /// See [`State`] for more details on how library authors should use this trait. /// /// This trait can be derived using `#[derive(FromRef)]`. /// /// [`State`]: https://docs.rs/axum/0.8/axum/extract/struct.State.html +/// [sharing-state]: https://docs.rs/axum/0.8/axum/index.html#sharing-state-with-handlers // NOTE: This trait is defined in axum-core, even though it is mainly used with `State` which is // defined in axum. That allows crate authors to use it when implementing extractors. pub trait FromRef { diff --git a/axum/src/docs/routing/with_state.md b/axum/src/docs/routing/with_state.md index 16bd1465..eda2344b 100644 --- a/axum/src/docs/routing/with_state.md +++ b/axum/src/docs/routing/with_state.md @@ -1,6 +1,13 @@ Provide the state for the router. State passed to this method is global and will be used for all requests this router receives. That means it is not suitable for holding state derived from a request, such as authorization data extracted in a middleware. Use [`Extension`] instead for such data. +See ["Sharing state with handlers"][sharing-state] for an overview of state patterns, +including when to use `Arc`, how to extract substates with [`FromRef`], and what the +`Router` type parameter means. + +[sharing-state]: crate#sharing-state-with-handlers +[`FromRef`]: crate::extract::FromRef + ```rust use axum::{Router, routing::get, extract::State}; diff --git a/axum/src/extract/state.rs b/axum/src/extract/state.rs index 915b73d2..13e0313d 100644 --- a/axum/src/extract/state.rs +++ b/axum/src/extract/state.rs @@ -7,12 +7,17 @@ use std::{ /// Extractor for state. /// +/// See ["Sharing state with handlers"][sharing-state] for an overview of all approaches to +/// sharing state, including when to use `Arc`, how `FromRef` substates work, and what the +/// `Router` type parameter means. +/// /// See ["Accessing state in middleware"][state-from-middleware] for how to /// access state in middleware. /// /// State is global and used in every request a router with state receives. /// For accessing data derived from requests, such as authorization data, see [`Extension`]. /// +/// [sharing-state]: crate#sharing-state-with-handlers /// [state-from-middleware]: crate::middleware#accessing-state-in-middleware /// [`Extension`]: crate::Extension /// diff --git a/axum/src/lib.rs b/axum/src/lib.rs index 03cd9979..3e3b4bd5 100644 --- a/axum/src/lib.rs +++ b/axum/src/lib.rs @@ -183,6 +183,51 @@ //! # let _: Router = app; //! ``` //! +//! State is cloned for every request. Wrapping your state in `Arc` makes those +//! clones cheap. If all fields are already cheap to clone (for example, each field +//! is itself an `Arc` or a copy type), you can `#[derive(Clone)]` directly on the +//! struct instead. +//! +//! ### Substates with `FromRef` +//! +//! When a handler only needs part of the application state, use [`FromRef`] to extract +//! a substate. Implement the trait manually, or derive it with `#[derive(FromRef)]` +//! (requires the `macros` feature): +//! +//! ```rust +//! use axum::{Router, routing::get, extract::{State, FromRef}}; +//! +//! #[derive(Clone)] +//! struct AppState { +//! api_state: ApiState, +//! } +//! +//! #[derive(Clone)] +//! struct ApiState {} +//! +//! // Teach axum how to produce an `ApiState` from a reference to `AppState`. +//! impl FromRef for ApiState { +//! fn from_ref(app_state: &AppState) -> ApiState { +//! app_state.api_state.clone() +//! } +//! } +//! +//! let app = Router::new() +//! .route("/", get(handler)) +//! .with_state(AppState { api_state: ApiState {} }); +//! +//! // This handler receives only the `ApiState` slice; it never sees `AppState`. +//! async fn handler(State(api_state): State) {} +//! # let _: Router = app; +//! ``` +//! +//! ### The `Router` type parameter +//! +//! `Router` when `S` is not `()` means a router that is _missing_ a state of type `S`. Calling +//! [`.with_state(s)`][Router::with_state] provides that state and typically produces a +//! `Router<()>`, which is the only form that can be passed to [`serve()`]. See +//! [`Router::with_state`] for a full explanation. +//! //! You should prefer using [`State`] if possible since it's more type safe. The downside is that //! it's less dynamic than task-local variables and request extensions. //! @@ -426,6 +471,8 @@ //! [load shed]: tower::load_shed //! [`axum-core`]: http://crates.io/crates/axum-core //! [`State`]: crate::extract::State +//! [`FromRef`]: crate::extract::FromRef +//! [`Router::with_state`]: crate::routing::Router::with_state #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(test, allow(clippy::float_cmp))]