Production Baseline

July 19, 2026 · View on GitHub

Recommended defaults for running RustAPI in production. This document describes what .production_defaults() enables and how to extend it for real workloads.

Start here first: Golden Path (example + walkthrough).

Related: Production Checklist · Deployment recipe · Observability recipe


One-call baseline

The fastest path to a production-shaped service:

use rustapi_rs::prelude::*;

#[rustapi_rs::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
    RustApi::auto()
        .production_defaults("my-service")
        .run("0.0.0.0:8080")
        .await
}

production_defaults(name) enables:

CapabilityWhat it does
Request IDsRequestIdLayer — every response gets a correlatable ID
TracingTracingLayer — structured spans per request
Health probes/health, /ready, /live without hand-written handlers
Service metadataService name attached to logs and health responses

For full control, use .production_defaults_with_config(ProductionDefaultsConfig::new()...).


Environment variables

VariablePurposeProduction value
RUSTAPI_ENVError masking for 5xx responsesproduction
RUST_LOGLog filter (when tracing subscriber is configured)info or warn
RUSTAPI_SERVICEOverride service name in logs/healthYour service name

In production, internal error details are masked to "An internal error occurred". Validation errors (4xx) pass through unchanged. Every 5xx includes an error_id (err_{uuid}) for log correlation.


Probe semantics

EndpointQuestion it answersRouting guidance
/liveIs the process alive?Use for liveness and startup probes
/readyShould this instance receive traffic?Point load balancers here
/healthWhat is aggregate dependency health?Dashboards and ops tooling

Rules of thumb:

  • Keep /live lightweight — no database calls.
  • Make /ready fail when critical dependencies are down or during graceful drain.
  • Use /health for richer dependency diagnostics.

Customize paths with HealthEndpointConfig if your platform requires different URLs.


Beyond production_defaults(), most production APIs add:

use rustapi_rs::extras::cors::CorsLayer;
use rustapi_rs::extras::rate_limit::{RateLimitLayer, RateLimitStrategy};
use rustapi_rs::extras::security_headers::SecurityHeadersLayer;
use rustapi_rs::extras::timeout::TimeoutLayer;
use rustapi_rs::prelude::*;

RustApi::auto()
    .production_defaults("billing-api")
    .layer(CorsLayer::new().allow_any_origin()) // tighten for production
    .layer(SecurityHeadersLayer::new())
    .layer(TimeoutLayer::new(std::time::Duration::from_secs(30)))
    .layer(RateLimitLayer::new(100).strategy(RateLimitStrategy::SlidingWindow))
LayerWhy
CorsLayerBrowser clients
SecurityHeadersLayerHSTS, CSP, X-Frame-Options defaults
TimeoutLayerPrevent hung handlers from tying up workers
RateLimitLayerAbuse protection on public endpoints
BodyLimitLayerDefault 1 MB; tune per upload routes

Use cargo rustapi new my-api --preset prod-api to scaffold a project with many of these features pre-selected.


Dependency-aware readiness

When your service depends on a database or cache, wire checks into HealthCheckBuilder:

let health = HealthCheckBuilder::new(true)
    .add_check("database", || async {
        // ping your pool; return HealthStatus::unhealthy("...") on failure
        HealthStatus::healthy()
    })
    .build();

RustApi::auto()
    .with_health_check(health)
    .production_defaults("users-api")
    .run("0.0.0.0:8080")
    .await?;

/ready returns 503 when any registered check is unhealthy.


Graceful shutdown

Register shutdown hooks for connection draining:

RustApi::auto()
    .production_defaults("users-api")
    .on_shutdown(|| async {
        // flush buffers, close pools, stop background workers
    })
    .run_with_shutdown("0.0.0.0:8080", shutdown_signal())
    .await?;

All run* entrypoints (run, run_http3, run_dual_stack, and *_with_shutdown variants) execute on_shutdown hooks after the server exits.


Observability baseline

SignalRustAPI primitive
Request correlationRequestIdLayer (in production_defaults)
Distributed tracingTracingLayer + optional extras-otel
MetricsMetricsLayer + /metrics when enabled
Structured logsextras-structured-logging
Admin visibilitycore-dashboard + optional extras-replay

See the Observability recipe for OpenTelemetry wiring and dashboard setup.


Security baseline

ConcernRecommendation
SecretsNever commit .env; use your platform's secret manager
JWTRotate signing keys; use JwtLayer::skip_paths for public routes
Admin surfacesProtect /__rustapi/dashboard and replay APIs with admin_token
CSRFEnable for cookie-session apps — see CSRF recipe
Error leakageSet RUSTAPI_ENV=production

Validate before deploy

Run the CLI doctor against your project:

cargo rustapi doctor --strict

Doctor checks toolchain availability and scans your workspace for production signals (production_defaults, health endpoints, shutdown hooks, rate limiting, etc.). See Production Checklist for the full manual list.


Deployment options

PathWhen to use
Self-hosted (Docker/K8s)Full control, existing infra
RustAPI CloudManaged hosting via cargo rustapi deploy cloud
Fly.io / Railway / ShuttlePlatform-specific generated configs

License

MIT OR Apache-2.0, at your option.