# Application State
Modern web applications are rarely stateless. You need a way to pass database connections, configuration parameters, or caching layers to your request handlers. Actix Web's web::Data extractor solves this elegantly.
##Initializing State
State in Actix Web is tied to the App instance. Because HttpServer creates a new App for every worker thread, you must wrap state in web::Data before passing it into the server factory if you want that state shared globally.
use actix_web::{web, App, HttpServer};
use std::sync::Mutex;
struct AppState {
app_name: String,
counter: Mutex<u32>, // Mutex needed for mutation
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let state = web::Data::new(AppState {
app_name: String::from("My Awesome App"),
counter: Mutex::new(0),
});
HttpServer::new(move || {
App::new()
.app_data(state.clone()) // Inject the state
// ... routes ...
})
.bind("127.0.0.1:8080")?
.run()
.await
}##Extracting State
Inside your handler, you use the web::Data extractor to access the state. The type signature MUST exactly match what you injected in main.
use actix_web::{web, Responder};
async fn index(data: web::Data<AppState>) -> impl Responder {
let mut count = data.counter.lock().unwrap();
*count += 1;
format!("Welcome to {}, visitor number {}!", data.app_name, count)
}##Common Use Case: Database Pools
The most common item placed in App State is a database connection pool (like sqlx::PgPool or r2d2). Since connection pools are inherently designed to be safely shared across threads, you often do not need to wrap them in a Mutex.
// Assuming sqlx::PgPool
// let pool = PgPoolOptions::new().connect("postgres://...").await?;
// let data = web::Data::new(pool);Inside the handler, you can extract web::Data<PgPool> and pass a reference to it to your SQL queries.
##Thread-Local State
If you actually want state to be unique per worker thread (e.g., a thread-local cache), you initialize it inside the HttpServer::new() closure, rather than outside.