rust 53 lines · 7 steps

Hot-reloadable config with shared state in Axum

An Axum service holds its config behind a shared read-write lock so handlers can serve it and reload it live without a restart.

Explained by highlit
1use std::sync::Arc;
2use std::collections::HashMap;
3use axum::{
4 extract::State,
5 http::StatusCode,
6 routing::{get, post},
7 Json, Router,
8};
9use serde::Serialize;
10use tokio::sync::RwLock;
11 
12#[derive(Clone)]
13struct AppState {
14 config: Arc<RwLock<AppConfig>>,
15}
16 
17#[derive(Clone, Serialize, Default)]
18struct AppConfig {
19 feature_flags: HashMap<String, bool>,
20 rate_limit: u32,
21 maintenance_mode: bool,
22}
23 
24async fn load_config() -> AppConfig {
25 let raw = tokio::fs::read_to_string("config/app.json")
26 .await
27 .unwrap_or_default();
28 serde_json::from_str(&raw).unwrap_or_default()
29}
30 
31async fn get_config(State(state): State<AppState>) -> Json<AppConfig> {
32 let config = state.config.read().await;
33 Json(config.clone())
34}
35 
36async fn reload_config(State(state): State<AppState>) -> Result<StatusCode, StatusCode> {
37 let fresh = load_config().await;
38 let mut config = state.config.write().await;
39 *config = fresh;
40 Ok(StatusCode::NO_CONTENT)
41}
42 
43pub async fn build_router() -> Router {
44 let initial = load_config().await;
45 let state = AppState {
46 config: Arc::new(RwLock::new(initial)),
47 };
48 
49 Router::new()
50 .route("/config", get(get_config))
51 .route("/config/reload", post(reload_config))
52 .with_state(state)
53}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Wrapping mutable state in Arc<RwLock<T>> lets many handlers read concurrently while writes stay exclusive and safe.
  2. 2unwrap_or_default keeps startup resilient, falling back to a usable config when a file is missing or malformed.
  3. 3Cloning state into the router via with_state gives every handler cheap, thread-safe access to the same data.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Hot-reloadable config with shared state in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code