docs: consolidate state management docs in crate root (#3683)

Co-authored-by: Yann Simon <[email protected]>
This commit is contained in:
kaze
2026-03-24 10:13:40 +01:00
committed by GitHub
co-authored by Yann Simon
parent a3446d68bc
commit 7c7a03927a
4 changed files with 61 additions and 1 deletions
+2 -1
View File
@@ -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<T> {
+7
View File
@@ -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<S>` type parameter means.
[sharing-state]: crate#sharing-state-with-handlers
[`FromRef`]: crate::extract::FromRef
```rust
use axum::{Router, routing::get, extract::State};
+5
View File
@@ -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<S>` 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
///
+47
View File
@@ -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<AppState> 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<ApiState>) {}
//! # let _: Router = app;
//! ```
//!
//! ### The `Router<S>` type parameter
//!
//! `Router<S>` 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))]