| Crates.io | axum-conf |
| lib.rs | axum-conf |
| version | 0.3.16 |
| created_at | 2025-12-30 11:14:44.002538+00 |
| updated_at | 2026-01-20 10:18:59.642183+00 |
| description | A library to simplify the use of Axum, Tokio and Postgres together using configuration. It comes with batteries included and many features can be feature activated. |
| homepage | |
| repository | https://github.com/macprog-guy/axum-conf-rs.git |
| max_upload_size | |
| id | 2012492 |
| size | 1,049,518 |
Production-ready web services with Axum — batteries included.
Build Kubernetes-native Rust services without the boilerplate. axum-conf gives you health probes, metrics, security headers, rate limiting, and more — all configured through simple TOML.
axum-conf
┌─────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Config │──▶│ FluentRouter │──▶│ Middleware │ │
│ │ (TOML) │ │ Builder │ │ Stack │ │
│ └─────────────┘ └──────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Production-Ready Server │ │
│ │ • Health probes • Metrics • Security headers │ │
│ │ • Rate limiting • CORS • Graceful shutdown│ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
1. Add to Cargo.toml:
[dependencies]
axum-conf = "0.3"
axum = "0.8"
tokio = { version = "1", features = ["full"] }
2. Create config/dev.toml:
[http]
bind_port = 3000
max_payload_size_bytes = "1MiB"
3. Write src/main.rs:
use axum::{Router, routing::get};
use axum_conf::{Config, Result, FluentRouter};
async fn hello() -> &'static str {
"Hello, World!"
}
#[tokio::main]
async fn main() -> Result<()> {
let config = Config::default();
config.setup_tracing();
FluentRouter::without_state(config)?
.route("/", get(hello))
.setup_middleware()
.await?
.start()
.await
}
4. Run:
RUST_ENV=dev cargo run
5. Test it:
curl http://localhost:3000/ # Your handler
curl http://localhost:3000/live # Liveness probe
curl http://localhost:3000/ready # Readiness probe
curl http://localhost:3000/metrics # Prometheus metrics
| Feature | What it does | Default |
|---|---|---|
| Health probes | /live and /ready endpoints for Kubernetes |
Enabled |
| Prometheus metrics | Request counts, latencies at /metrics |
Enabled |
| Request logging | Structured logs with UUIDv7 correlation IDs | Enabled |
| Rate limiting | Per-IP request throttling | 100 req/sec |
| Security headers | X-Frame-Options, X-Content-Type-Options | Enabled |
| Static files | Serve assets, SPAs, protected downloads | Available |
| Panic recovery | Catches panics, returns 500, keeps running | Enabled |
| Graceful shutdown | Handles SIGTERM, drains connections | 30s timeout |
| Compression | gzip, brotli, deflate, zstd | Available |
Enable optional capabilities by category:
| Feature | What it adds |
|---|---|
postgres |
PostgreSQL connection pooling with sqlx |
keycloak |
OIDC/JWT authentication via Keycloak |
basic-auth |
HTTP Basic Auth and API key authentication |
session |
Cookie-based session management |
opentelemetry |
Distributed tracing with OTLP export |
rustls |
TLS support (auto-enabled by postgres) |
circuit-breaker |
Per-target circuit breaker for external services |
openapi |
OpenAPI spec generation via utoipa |
| Feature | What it adds |
|---|---|
metrics |
Prometheus metrics at /metrics |
rate-limiting |
Per-IP request throttling |
security-headers |
Security headers (X-Frame-Options, etc.) |
deduplication |
Request deduplication by request ID |
compression |
gzip/brotli/deflate/zstd compression |
cors |
CORS handling |
api-versioning |
API version extraction (path/header/query) |
concurrency-limit |
Max concurrent request limiting |
path-normalization |
Trailing slash normalization |
sensitive-headers |
Authorization header redaction in logs |
payload-limit |
Request body size limits |
| Group | Includes |
|---|---|
production |
metrics, rate-limiting, security-headers, compression, cors |
full |
All features |
# Example: Production setup with PostgreSQL
axum-conf = { version = "0.3", features = ["production", "postgres"] }
Most features work together, with one important exception:
| Feature | Compatible With | Notes |
|---|---|---|
keycloak |
All except basic-auth |
Automatically enables session |
basic-auth |
All except keycloak |
Cannot be used with OIDC |
postgres |
All features | Independent database layer |
session |
All features | Required by keycloak |
opentelemetry |
All features | Independent tracing layer |
Important: keycloak and basic-auth are mutually exclusive. Choose one authentication method per application.
Run the examples to see axum-conf in action:
# Basic hello world
cargo run --example hello_world
# Application state management
cargo run --example with_state
# JSON REST API
cargo run --example json_api
# Middleware configuration (requires features)
cargo run --example with_middleware --features "cors,compression,rate-limiting"
# config/prod.toml
[http]
bind_addr = "0.0.0.0"
bind_port = 8080
max_payload_size_bytes = "32KiB"
request_timeout = "30s"
max_requests_per_sec = 1000
[http.cors]
allowed_origins = ["https://app.example.com"]
allowed_methods = ["GET", "POST", "PUT", "DELETE"]
[database]
url = "{{ DATABASE_URL }}"
max_pool_size = 10
[logging]
format = "json"
The default setup_tracing() configures logging based on your LoggingConfig. When you need additional tracing layers (OpenTelemetry, file appenders, custom filters), use setup_tracing_with():
use axum_conf::Config;
use tracing_subscriber::layer::SubscriberExt;
let config = Config::default();
// Add custom layers while keeping the configured fmt layer and env filter
config.setup_tracing_with(|subscriber| {
subscriber
.with(tracing_opentelemetry::layer().with_tracer(tracer))
.with(my_file_appender_layer)
});
The callback receives a TracingBase subscriber with the fmt layer (respecting your logging.format setting) and EnvFilter already applied. Add your layers with .with() and return the result.
| Guide | Description |
|---|---|
| Getting Started | Build your first service step-by-step |
| Architecture | How axum-conf works under the hood |
| Configuration | |
| Overview | Configuration methods and philosophy |
| TOML Reference | Complete configuration schema |
| Environment Variables | Using {{ VAR }} substitution |
| Features | |
| PostgreSQL | Database integration guide |
| Keycloak/OIDC | Authentication setup |
| OpenTelemetry | Distributed tracing |
| Basic Auth | Simple authentication |
| Sessions | Session management |
| Circuit Breaker | External service resilience |
| OpenAPI | API documentation generation |
| Deduplication | Request deduplication |
| TLS/rustls | TLS configuration |
| Static Files | Asset serving and SPA support |
| Middleware | |
| Overview | Middleware stack architecture |
| Features | API versioning, limits, normalization |
| Security | Rate limiting, CORS, headers |
| Observability | Logging, metrics, tracing |
| Performance | Compression, timeouts, limits |
| Kubernetes | |
| Health Checks | Liveness and readiness probes |
| Graceful Shutdown | Proper pod termination |
| Deployment | Complete K8s manifests |
| Reference | |
| Troubleshooting | Common issues and solutions |
| API Docs | Rustdoc API reference |
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-service
spec:
template:
spec:
containers:
- name: app
image: my-service:latest
ports:
- containerPort: 8080
env:
- name: RUST_ENV
value: "prod"
livenessProbe:
httpGet:
path: /live
port: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
terminationGracePeriodSeconds: 35
MIT