Expand description
rustango — a Django-shaped, batteries-included web framework for Rust.
ORM with auto-migrations, auto-admin, multi-tenancy, sessions +
JWT + OAuth2/OIDC + HMAC auth, DRF-style serializers + viewsets,
signals, caching, media (S3/R2/B2/MinIO), email pipeline,
background jobs, scheduled tasks, OpenAPI 3.1 auto-derive, every
standard middleware. Postgres + MySQL through the same &Pool
API, opt-in via Cargo features.
[dependencies]
rustango = "0.23"Defaults (["postgres", "admin"]) get you the ORM, migration
runner, and auto-admin. Add "tenancy" for the multi-tenant
resolver / pools / per-tenant auth pieces, "mysql" for MySQL
8.0+ alongside Postgres, or drop default-features for the bare
ORM (no axum, no Tera).
§Quick start
cargo install cargo-rustango
cargo rustango new myblog # default: ORM + admin
cargo rustango new myapi --template api # JSON-only, no admin
cargo rustango new shop --template tenant # multi-tenancy + operator consoleThen:
cd myblog
cp .env.example .env # set DATABASE_URL
cargo run -- migrate # apply bootstrap migrations
cargo run # http://localhost:8080§Unified manage runner (since v0.16)
Since v0.16 there is one binary that serves HTTP and dispatches
manage commands. cargo run starts the server; cargo run -- <verb>
runs a CLI command. A scaffolded src/main.rs looks like:
#[rustango::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = dotenvy::dotenv();
rustango::manage::Cli::new()
.api(myblog::urls::router())
.tenancy() // optional, with `tenancy` feature
.migrations_dir(std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("migrations"))
.run()
.await
}Common manage verbs (every command supports --help):
| Group | Verbs |
|---|---|
| Migrations | makemigrations, migrate [target], downgrade [N], showmigrations, add-data-op |
| Scaffolders | startapp <name>, make:viewset, make:serializer, make:form, make:job, make:notification, make:middleware, make:test |
| System | about, check, check --deploy, version, docs |
| Tenancy | create-tenant, create-operator, create-user, list-tenants, create-api-key, grant-perm, revoke-perm, audit-cleanup |
§Full reference
See the workspace README
for the complete feature matrix, ORM cookbook, viewset / serializer
recipes, multi-tenancy guide, and production checklist. The
examples/cookbook_blog
crate ships a runnable multi-tenant blog with one chapter per
feature surface.
Re-exports§
pub use sql::Auto;pub use rustango_macros as macros;
Modules§
- access_
log - HTTP access log middleware — one tracing event per request with
method / path / status / duration / IP. See
access_log::AccessLogLayer. HTTP access log middleware — emit one tracing event per request. - account_
lockout - Per-account login lockout — defends against credential stuffing.
Cache-backed counter + lock flag. See
account_lockout::Lockout. Per-account login lockout — defends against credential stuffing / brute-force attacks that bypass per-IP rate limits. - admin
- Auto-generated CRUD admin for rustango models.
- api_
errors - Standardized API error responses. See
api_errors::ApiError. Standardized API error responses. - api_
keys - Generic API key generation + verification (argon2id-hashed).
See
api_keys::generate_key/api_keys::verify_key. Generic API key generation and verification. - api_
version - API versioning — extract version from header / query / URL prefix.
See
api_version::VersionStrategyandapi_version::ApiVersion. API versioning extractor — read the requested API version from URL, header, or query parameter. - audit
- Audit log — single composite-key table that captures every
tracked write (insert, update, delete, soft-delete) across every
model whose declaration carries
#[rustango(audit(...))]. - auth_
flows - Pre-built auth flows — password reset, email verification, magic-link login.
See
auth_flows::PasswordReset/auth_flows::EmailVerification. Pre-built auth flows — password reset + email verification. - body_
limit - Request body size limit middleware — fast
Content-Lengthrejection returning structured413 Payload Too LargeJSON. Complements axum’s per-extractorDefaultBodyLimit. Seebody_limit::BodyLimitLayer. Request body size limit middleware. - cache
- Pluggable caching layer —
cache::Cachetrait +cache::NullCache+cache::InMemoryCache. Redis backend behind thecache-redisfeature. Pluggable caching layer. - compression
- Response compression middleware — gzip + deflate via flate2.
Honors
Accept-Encoding, skips already-compressed bodies and binary content-types. Seecompression::CompressionLayer. Response compression middleware — gzip + deflate. - config
- Layered TOML configuration (slice 8.3).
- content_
negotiation - HTTP content negotiation — pick the best response format from the
client’s
Acceptheader. Seecontent_negotiation::negotiate. HTTP content negotiation — pick the best response format from the client’sAcceptheader. - contenttypes
- ContentType framework (Django-shape) — runtime handle for “any registered model” used by permissions, generic foreign keys, soft-FK prefetch, audit-history admin panels, etc. Sub-slice F.1 of the v0.15.0 plan. Django-shape ContentType framework — sub-slice F.1 of v0.15.0.
- core
- Core types for rustango.
- cors
- CORS middleware —
cors::CorsLayerfor axum routers. CORS middleware — Cross-Origin Resource Sharing for axum routers. - csp_
nonce - Per-request CSP nonce middleware — generates a fresh CSPRNG nonce
per request, makes it available via
Extension<Nonce>, and substitutes'nonce-__RUSTANGO_NONCE__'in the CSP header so inline<script nonce="...">tags pass strict CSP. Seecsp_nonce::CspNonceLayer. Per-request CSP nonce middleware. - csv
- Minimal RFC 4180 CSV writer — zero deps. See
csv::CsvWriter. Minimal CSV writer — RFC 4180 compliant, zero deps. - csv_
response - axum response wrapper for CSV exports — sets Content-Type +
optional Content-Disposition so browsers prompt a “Save as…”
download. See
csv_response::CsvResponse. axum response wrapper for CSV exports — sets the rightContent-Type+ an optionalContent-Dispositionso browsers prompt a “Save as…” download. - distributed_
lock - Distributed locks backed by
cache::Cache— “only one worker at a time runs this task” with TTL-based crash recovery and token-checked release. Seedistributed_lock::DistributedLock. Distributed locks backed byCache. - Email backends —
email::Mailertrait + console/in-memory/null backends. Email backend layer — pluggable async email sending. - email_
jobs - Send email off the request path via the
crate::jobsqueue. Pairs theemail::Mailertrait with the queue’s retry-with- backoff so transient SMTP failures don’t blow up handlers. Seeemail_jobs::register_email_job+email_jobs::dispatch_email. Send email off the request path via thecrate::jobsqueue. - email_
templates - Tera-rendered email helpers — bridge
crate::emailmailers and the Tera templating engine. Each email =<name>.subject.txt+<name>.txt+ optional<name>.html. Seeemail_templates::EmailRenderer. Tera-rendered email helpers — bridge the existingcrate::emailmailer trait and the Tera templating engine (already a dep on theadminfeature). - env
- Typed environment variable readers —
required/with_default/optional/list/duration_secs/duration_millis. Typed environment variable readers — pydantic-settings / django-environ shape. - etag
- ETag middleware — hashes 2xx response bodies, returns 304 when
If-None-Matchmatches. Seeetag::EtagLayer. ETag middleware — hashes response bodies and serves304 Not Modifiedwhen the client’sIf-None-Matchmatches. - feature_
flags - Feature flags / killswitches backed by
cache::Cache— boolean killswitch + per-user override + stable percentage rollout. Seefeature_flags::FeatureFlags. Feature flags / killswitches backed by theCachetrait. - fixtures
- Test fixture loader — seed a database from JSON files.
See
fixtures::Fixture. Test fixture loader — seed a test database from JSON files. - forms
- Form parsing, validation, and saving — shared between the auto-admin and user route handlers.
- health
- Health check endpoints —
/health(liveness) +/ready(readiness). Seehealth::health_router. Health check endpoints —/health(liveness) and/ready(readiness). - hmac_
auth - AWS-style canonical request signed with SHA-256, replay-bounded
by an X-Date tolerance window. See
hmac_auth::HmacAuthLayer. HMAC-signed request authentication for service-to-service traffic. - http_
client - Opinionated HTTP client —
reqwestwrapper with sane timeouts, retry on idempotent verbs / transient failures, default User-Agent. Seehttp_client::HttpClient. Opinionated HTTP client —reqwestwrapper with sane timeouts, exponential-backoff retries on idempotent verbs / transient failures, and a defaultUser-Agent. - i18n
- Internationalization (i18n) — translation lookups + Accept-Language negotiation.
See
i18n::Translatorandi18n::negotiate_language. Internationalization (i18n) — translation lookups + Accept-Language negotiation. - idempotency
- Idempotency-key middleware (Stripe-shape) — replays a stored
successful response when a write request arrives with the same
Idempotency-Key. Backed by anycache::Cache. Seeidempotency::IdempotencyLayer. Idempotency-key middleware (Stripe-shape). - ip_
filter - IP allowlist / blocklist middleware. See
ip_filter::IpFilterLayer. IP allowlist / blocklist middleware — gate routes by client IP. - jobs
- Background job queue with worker pool — async work outside the request
lifecycle. Currently in-memory only. See
jobs::JobQueue. Background job queue — async work outside the request lifecycle. - jsonapi
- JSON:API v1.1 response envelope adapter — wrap a flat
serde_json::Value(typicalserializeroutput) into the{"data": {"type", "id", "attributes": {...}}}shape that JSON:API clients expect. Seejsonapi::to_resource+jsonapi::to_collection. JSON:API v1.1 response shape adapter. - jwt
- Standalone HS256 JWT — sign / verify / decode for magic links,
microservice tokens, third-party SSO. See
jwt::encode+jwt::decode. Minimal JWT (HS256) — sign, verify, decode. - logging
- One-call tracing-subscriber setup. See
logging::setup/logging::Setup. Tracing-subscriber setup helpers — the boilerplate every rustango app writes by hand becomes one call. - mailable
- Laravel-shape
Mailabletrait — declare an email type as a struct that owns its template + recipient logic. Pairs withemail_templates::EmailRenderer(rendering) andemail_jobs(off-request delivery). Seemailable::Mailable. Laravel-shapeMailabletrait — declare an email type as a struct that owns its own template + recipient logic. Pairs withcrate::email_templates::EmailRenderer(template rendering) andcrate::email_jobs(off-request delivery). - maintenance
- Maintenance-mode middleware — return 503 with
Retry-Afterfrom a shared atomic flag, so an orchestrator can drain traffic before a deploy / migration without killing in-flight requests. Seemaintenance::MaintenanceFlag+maintenance::MaintenanceLayer. Maintenance-mode middleware — return 503 withRetry-Afterfrom a shared flag, so an orchestrator (or a sidecar) can drain traffic before a deploy / migration without killing in-flight requests. - manage
- Unified manage runner — collapses
src/main.rs+src/bin/manage.rsboilerplate into onemanage::Clibuilder. Tenancy variant available when thetenancyfeature is on. Behind themanagefeature (default-on) which pulls a minimal axum + tokio surface so bare-API projects (no admin) can still use the dispatcher. Unified manage runner — collapsessrc/main.rs+src/bin/manage.rsboilerplate into one builder so apps stop hand-writing the dispatcher. - media
- First-class
Mediamodel — Postgres-backed file references with direct-browser upload, CDN-aware URLs, soft delete + orphan purge. Seemedia::Media+media::MediaManager. First-classMediamodel — a real#[derive(Model)]row that references a file in thecrate::storage::Storagelayer. - method_
override - HTTP method override — rewrite POST → PUT/PATCH/DELETE based on
X-HTTP-Method-Overrideheader or_methodform field, so HTML forms can drive REST routes. Seemethod_override::MethodOverrideLayer. HTTP method override — rewrite POST → PUT / PATCH / DELETE based on a hidden form field or header. - metrics
- Prometheus-format metrics — counters + histograms exposed at
/metrics. Pure-Rust, no Prometheus client crate. Seemetrics::MetricsRegistry+metrics::metrics_router. Prometheus-format metrics — counters + histograms exposed at/metrics. - migrate
- Migrations for rustango.
- notifications
- Multi-channel notifications — fan one notification out to mail / database /
log / broadcast channels. See
notifications::notify. Multi-channel notifications — fan one notification out to mail / database / log / broadcast channels. - oauth2
- OAuth2 / OIDC swiss-knife — social login that works for both pure
OAuth2 (GitHub, Discord) and OIDC (Google, Microsoft, Keycloak)
providers via the
/userinfoendpoint. Per-tenant viaoauth2::OAuth2Registry. Optional axum router underoauth2::router(requires theadminfeature). OAuth2 / OIDC swiss-knife — one type, every provider. - openapi
- OpenAPI 3.1 spec builder + Swagger UI / Redoc viewer routes.
Hand-build a spec with
openapi::OpenApiSpecand mount it underopenapi::router::openapi_router(requires theadminfeature). OpenAPI 3.1 spec builder + optional Swagger UI router. - pagination
- Pagination helpers — RFC 5988 Link headers + cursor params.
See
pagination::LinkHeaderBuilder. Pagination helpers — Link headers (RFC 5988) + cursor parameters. - passwords
- Generic password hash/verify + strength heuristic. See
passwords::hash. Generic password hashing + strength checking. - problem_
details - RFC 7807 “Problem Details for HTTP APIs” — standardized error
responses with
application/problem+json. Sister toapi_errors. Seeproblem_details::ProblemDetails. RFC 7807 “Problem Details for HTTP APIs” — standardized error responses with the canonicalapplication/problem+jsoncontent type. - query
- Query layer for rustango.
- rate_
limit - Token-bucket rate limiting middleware —
rate_limit::RateLimitLayer. Per-IP, per-header, or global. Returns 429 withRetry-Afterwhen exhausted. Token-bucket rate limiting middleware for axum routers. - rate_
limit_ cache - Cache-backed rate limiting middleware — fixed-window counter via the
cache::Cachetrait. Pair withRedisCachefor distributed enforcement across multiple processes / replicas. Seerate_limit_cache::CacheRateLimitLayer. Distributed rate limiting via theCachetrait. - real_ip
- Real-IP extraction for apps behind a trusted reverse proxy
(Cloudflare / nginx / ELB / etc). Parses
X-Forwarded-For,X-Real-IP,CF-Connecting-IP, or RFC 7239Forwardedand stuffs the resolved client IP into request extensions. Seereal_ip::RealIpLayer. Real-IP extraction middleware for apps behind a trusted reverse proxy. - request_
id - Request ID middleware — assign per-request correlation IDs,
honor inbound
X-Request-Idfor end-to-end propagation. Seerequest_id::RequestIdLayer. Request ID middleware — assign a unique ID to every incoming request. - scheduler
- In-process scheduled task runner — fire async jobs at fixed intervals.
See
scheduler::Scheduler. In-process scheduled task runner — fire async jobs at fixed intervals. - secrets
- Pluggable secrets backend —
secrets::Secretstrait +secrets::EnvSecrets - security_
headers - Security headers middleware — HSTS / X-Frame-Options / nosniff /
Referrer-Policy / Permissions-Policy / CSP. See
security_headers::SecurityHeadersLayer. Security headers middleware — HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Cross-Origin-Opener-Policy, and a Content-Security-Policy builder. - serializer
- DRF-style serializer layer —
#[derive(Serializer)]+serializer::ModelSerializer. Typed JSON output from model instances with field control and validation. DRF-style serializer layer — typed JSON output from model instances. - server_
timing Server-Timingheader middleware — surface per-request stage durations to the browser DevTools “Network” panel. Seeserver_timing::ServerTimingLayer+server_timing::Timings.Server-Timingheader middleware — surface per-request stage durations to the browser DevTools “Network → Timing” panel.- sessions
- Server-side sessions backed by
cache::Cache— opaque cookie ID, server-stored bag of typed values, revocable per-session. Seesessions::Session+sessions::SessionStore. Server-side session store backed bycrate::cache::Cache. - signals
- Django-shape model signals —
signals::connect_post_saveetc. Receivers register globally per model type and run sequentially. Django-shape model signals —pre_save,post_save,pre_delete,post_delete. - signed_
url - Signed URL helpers — HMAC-SHA256 with optional expiry.
See
signed_url::sign/signed_url::verify. Signed URL helpers — tamper-evident URLs with optional expiry. - soft_
delete - Soft-delete query helpers —
active_filter/trashed_filter/compose_with_active/soft_delete/restore/purgefor any model carrying#[rustango(soft_delete)]. Seesoft_delete. Soft-delete query helpers. - sql
- SQL compilation and execution for rustango.
- sse
- Broadcast event bus — fan-out for SSE / WebSocket / signal-driven push.
See
sse::EventBus. Broadcast event bus — fan one message out to every connected subscriber. The foundation for Server-Sent Events (SSE) and other real-time push patterns. - static_
files - Static file serving — read files from a directory with sensible
Content-Type,Cache-Control,Last-Modified, and 304 support. Seestatic_files::StaticFiles+static_files::static_router. Static file serving — read files from a directory and ship them with sensibleContent-Type,Cache-Control, andLast-Modifiedheaders, plusIf-Modified-Since304 support. - storage
- File storage backends —
storage::Storagetrait + LocalStorage + InMemoryStorage. File storage backends — upload, retrieve, delete files via a pluggable trait. - test_
client - Test client — fire HTTP requests against an
axum::Routerin tests without binding a real socket. Seetest_client::TestClient. Test client — fire HTTP requests against anaxum::Routerin tests without binding a real socket. - text
- Text utilities — slugify, html_escape, truncate. Text utilities — slug generation, HTML escaping, truncation.
- totp
- TOTP — RFC 6238 time-based one-time passwords for 2FA.
See
totp::generate/totp::verify/totp::otpauth_url. TOTP — Time-based One-Time Passwords (RFC 6238) for 2FA. - tracing_
layer - Per-request
tracingspan with W3C / OpenTelemetry-conventional field names +traceparentheader propagation. Hooktracing_opentelemetry::layer()in your subscriber for free distributed tracing. Seetracing_layer::TracingLayer. Per-requesttracingspan with W3C / OpenTelemetry-conventional field names +traceparentheader propagation. - trailing_
slash - Trailing-slash redirect middleware — canonicalize URL paths
(Django
APPEND_SLASH/ Railstrailing_slashshape). Seetrailing_slash::TrailingSlashLayer. Trailing-slash redirect middleware — canonicalize URL paths. - uploads
- Multipart file upload helper — wraps axum’s multipart extractor +
the
storage::Storagetrait. Seeuploads::save_uploads+uploads::UploadConfig. Multipart file upload helper — wraps axum’s multipart extractor + thecrate::storage::Storagetrait so a file upload handler is a one-liner instead of buffering / size-checking / extension- validating glue. - webhook
- Webhook signature verification (HMAC-SHA256). See
webhook::verify_signature. Webhook signature verification — HMAC-based, constant-time. - webhook_
delivery - Outbound webhook delivery — POSTs HMAC-signed JSON via the background
job queue (so retries with exponential backoff are free). See
webhook_delivery::WebhookSubscription. Outbound webhook delivery — POSTs an HMAC-signed JSON payload to a subscriber URL via the background job queue. - welcome
- First-run welcome page — confidence signal that rustango is wired up.
Mount under
/while bootstrapping; replace once you have content. Seewelcome::welcome_router. First-run welcome page — confidence signal that rustango is wired up. - ws
- WebSocket handler scaffold — fan-out via
sse::EventBuswith auto JSON encode/decode + keep-alive ping. Seews::WsHub+ws::ws_handler. WebSocket handler scaffold — fan-out via the SSE [EventBus].
Macros§
- embed_
migrations - Bake every migration file in a directory into the binary at
compile time, for shipping a single-binary distribution. Pair
with
migrate::migrate_embedded. Bake every*.jsonmigration file in a directory into the binary at compile time. Returns a&'static [(&'static str, &'static str)]of(name, json_content)pairs, lex-sorted by file stem.
Enums§
- Rustango
Error - Unified error type for app-level code.
Fromimpls cover every module in the framework so?Just Works in handlers.
Type Aliases§
- Rustango
Result - Standard alias.
Attribute Macros§
- main
#[rustango::main]— the Django-shaperunserverentrypoint. Wraps#[tokio::main]with a defaulttracing-subscriberboot (env-filter, falling back toinfo,sqlx=warn). Available behind theruntimefeature, whichtenancyimplies.#[rustango::main]— the Django-shape runserver entrypoint. Wraps#[tokio::main]and a defaulttracing_subscriberinitialisation (env-filter, falling back toinfo,sqlx=warn) so usermainfunctions are zero-boilerplate:
Derive Macros§
- Form
#[derive(Form)]— implementsforms::Formso a struct can be parsed from an HTTP form payload with multi-error validation. Re-exported only when theformsfeature is on. Deriverustango::forms::FormStruct(slice 8.4B). Generates aparse(&HashMap<String, String>) -> Result<Self, FormError>impl that walks every named field and:- Model
#[derive(Model)]— populates theinventoryregistry the admin walks, generatesobjects()/ typed columns /insert/delete/save. Derive aModelimpl. See crate docs for the supported attributes.- Serializer
#[derive(Serializer)]— implementsserializer::ModelSerializeron a struct, generatingfrom_model, a customserde::Serialize(respectingwrite_only), andwritable_fields. Re-exported when theserializerfeature is on. Derive [rustango::serializer::ModelSerializer] for a struct.