Configuration & Secrets in Prod
Rust services follow twelve-factor config: store settings in the environment, load once at startup, and never commit secrets to git or bake them into images.
Search across all documentation pages
Rust services follow twelve-factor config: store settings in the environment, load once at startup, and never commit secrets to git or bake them into images.
[dependencies]
config = "0.14"
serde = { version = "1.0", features = ["derive"] }use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Settings {
database_url: String,
port: u16,
}
impl Settings {
fn from_env() -> Result<Self, config::ConfigError> {
config::Config::builder()
.add_source(config::Environment::default().separator("__"))
.build()?
.try_deserialize()
}
}When to reach for this:
# Kubernetes secret -> env
# env:
# - name: DATABASE_URL
# valueFrom:
# secretKeyRef:
# name: db-credentials
# key: url
export PORT=8080
export DATABASE_URL=postgres://user:pass@host/db
./my-service// Never log secrets
tracing::info!(port = settings.port, "listening");
// BAD: tracing::info!(?settings.database_url);What this demonstrates:
APP__DATABASE__URL style separators| Crate | Role |
|---|---|
config | Layered file + env |
figment | Flexible sources |
dotenvy | Local dev only (not prod loader) |
.env in production - file leakage risk. Fix: dotenvy for dev; orchestrator env in prod.RUST_LOG debug dumps - accidental exposure. Fix: structured logging with allowlists.| Alternative | Use When | Don't Use When |
|---|---|---|
| HashiCorp Vault agent | Dynamic DB creds | Simple static API keys |
| SOPS-encrypted files | Git-stored non-K8s deploys | Pure 12-factor K8s |
| Hard-coded defaults | Local dev ergonomics | Production secrets |
CI only. Runtime uses live DATABASE_URL.
Parse in main before binding sockets; exit non-zero with clear message.
Mount as files; read paths from env (TLS_CERT_PATH). Do not inline PEM in env vars.
Non-secret flags can live in ConfigMap; sensitive rollout keys stay in secret store.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026