Cookbook / Data and storage
Configuration from the environment
Load typed settings from environment variables and a .env file, with every problem reported at once.
config::from_env fills a struct from environment variables, so you get typed settings and a startup error that lists everything that is wrong, rather than a crash on the first missing value.
use axeon::{config, Json, Server};
use axeon::json;
use serde::Deserialize;
#[allow(dead_code)] // hand these to your database and cache clients
#[derive(Deserialize)]
struct Config {
database_url: String, // DATABASE_URL
port: u16, // PORT
allowed_origins: Vec<String>, // ALLOWED_ORIGINS=a.com,b.com
redis_url: Option<String>, // optional
}
fn main() {
config::load_dotenv().expect("invalid .env");
let config: Config = config::from_env().expect("invalid configuration");
let addr = format!("0.0.0.0:{}", config.port);
let origins = config.allowed_origins.clone();
let mut app = Server::new();
app.state(config);
app.get("/config", move |_req| {
let origins = origins.clone();
async move { Json(json!({ "origins": origins })) }
});
app.listen(&addr).expect("server failed to start");
}
# .env
DATABASE_URL=postgres://localhost/app
PORT=3000
ALLOWED_ORIGINS=https://a.example.com,https://b.example.com
Notes#
- Field names map to upper-case variables:
database_urlreadsDATABASE_URL. - Comma-separated values fill a
Vec; anOptionfield may be absent. - Real environment variables win over
.env, so production settings are never overridden by a stray file. - Keep secrets (JWT keys, database passwords) here, never in source.