Expand description
rustango — a batteries-included web framework for Rust.
It is built on one derive macro and one connection type, and ships a typed ORM with auto-migrations, an auto-generated admin, multi-tenancy, auth (sessions / JWT / OAuth2-OIDC / HMAC / passkeys), serializers and viewsets, signals, caching, media, email, background jobs, scheduled tasks, OpenAPI 3.1, and the usual production middleware.
Postgres, MySQL and SQLite all use the same sql::Pool and the same
#[derive(Model)] types. The backend is a Cargo feature, not a rewrite.
Everything is opt-in: take only the features you use, down to the bare ORM with no HTTP stack. Release history is in the CHANGELOG.
§Install
[dependencies]
rustango = "0.61" # Postgres (the default backend)
# or pick another backend — see "Choosing a backend" below:
rustango = { version = "0.61", default-features = false, features = ["sqlite", "batteries"] }
rustango = { version = "0.61", default-features = false, features = ["mysql", "batteries"] }default = ["postgres", "batteries"]. batteries is everything except
the backend (admin, serializers, auth, jobs, cache, media, middleware, …).
You pick the backend separately, so you can keep the batteries and still
choose your database. Drop batteries for the bare ORM (no axum, no Tera).
§A taste
use rustango::Model;
use rustango::sql::{Auto, Pool, FetcherPool};
// One derive gives a table, typed columns, migrations, and admin wiring.
#[derive(Model, Clone, Debug)]
#[rustango(table = "posts")]
struct Post {
#[rustango(primary_key)]
id: Auto<i64>, // server-assigned auto-increment PK
#[rustango(max_length = 200)]
title: String,
body: String,
published: bool,
}
// One connection type for every backend — the driver is chosen from the
// URL scheme (postgres://…, mysql://…, sqlite://…).
let pool = Pool::connect(&std::env::var("DATABASE_URL")?).await?;
// Chained queries, compiled to your dialect.
let recent: Vec<Post> = Post::objects()
.filter("published", true)
.order_by_desc("id")
.limit(10)
.fetch(&pool)
.await?;§Choosing a backend
The same models and queries emit Postgres, MySQL or SQLite SQL. You pick
the backend with a Cargo feature and the DATABASE_URL scheme.
- Connect with
sql::Pool::connect. It reads the URL scheme and builds the right pool. Prefer it oversqlx::PgPool::connect(...), which only exists when thepostgresfeature is on. sql::Poolis the enum every rustango API takes (&Pool). A concretesqlx::PgPool/SqlitePool/MySqlPoolconverts into it withFrom, so you can pass either.- Enable one backend feature (
postgres,mysql, orsqlite) for a single-database app. Enable several to build one binary that serves any of them. - Multi-tenancy works on all three:
tenancy::TenantPoolsis generic over the backend. Schema-mode tenancy is Postgres-only, because it usesSET search_path.
§Feature flags
| Feature | Gives you |
|---|---|
postgres / mysql / sqlite | The database backend(s). |
batteries | The default bundle minus the backend (see Install). |
admin | Auto-generated admin UI + session auth; #[derive(ViewSet)] REST endpoints (also under tenancy). |
tenancy | Multi-tenant resolver, per-tenant pools, operator console. |
serializer | #[derive(Serializer)] JSON serializers. |
jwt / oauth2 | Token auth; social / OIDC login. |
jobs / jobs-postgres | Background jobs (in-memory / durable). |
cache / cache-redis | Cache layer; Redis backend. |
storage / storage-s3 / storage-azure / media | File storage + the Media model. |
mcp | Model Context Protocol server over HTTP. |
openapi | OpenAPI 3.1 schema auto-derive. |
Every feature is listed in the crate’s Cargo.toml with a one-line note.
§Quick start (scaffolder)
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 console
cd myblog
cp .env.example .env # set DATABASE_URL
cargo run -- migrate # apply bootstrap migrations
cargo run # http://localhost:8080§The manage runner
One binary serves HTTP and dispatches CLI commands: cargo run starts the
server, cargo run -- <verb> runs a command. A scaffolded main.rs:
#[rustango::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = dotenvy::dotenv();
rustango::manage::Cli::new()
.api(myblog::urls::api())
.tenancy() // optional, with the `tenancy` feature
.run()
.await
}Common verbs (each supports --help):
| Group | Verbs |
|---|---|
| Migrations | makemigrations, migrate [target], downgrade [N], showmigrations |
| Scaffolders | startapp, make:viewset, make:serializer, make:form, make:job, make:middleware, make:test |
| System | about, check, check --deploy, version |
| Tenancy | create-tenant, create-operator, create-user, list-tenants, create-api-key, grant-perm, audit-cleanup |
§Where to look
- Models & queries —
core,sql - Admin —
admin - REST —
viewset,serializer - Multi-tenancy —
tenancy - Auth —
auth_backends,jwt,sso - Background work —
jobs,scheduler - Caching —
cache
The workspace README has the full
feature matrix and guides.
examples/cookbook_blog
is a runnable multi-tenant blog with one chapter per feature.
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. Stops credential stuffing and brute force that gets past per-IP rate limits. - admin
- Auto-generated CRUD admin for rustango models.
- api_
errors - Standardized API error responses. See
api_errors::ApiError. Needs only axum, so every HTTP surface can answer in this shape. One JSON shape for every API error, so clients can parse them all the same way. It follows RFC 7807 “Problem Details” loosely: - api_
keys - Generic API key generation + verification (argon2id-hashed).
See
api_keys::generate_key/api_keys::verify_key. Create and check API keys. - api_
version - API versioning — extract version from header / query / URL prefix.
See
api_version::VersionStrategyandapi_version::ApiVersion. Read the requested API version from the URL, a header or a query parameter. - audit
- Audit log — one table that records every tracked write (insert,
update, delete, soft-delete) for models declared with
#[rustango(audit(...))]. - auth_
backends - Pluggable
AUTHENTICATION_BACKENDSchain — register an ordered list ofauth_backends::AuthBackendimpls; the chain returns the first non-Noneresult. ShipsRemoteUserBackendfor SSO proxy setups. A chain of authentication backends, tried in order. - auth_
decorators - Access gates —
login_requiredmiddleware and?next=round-trip helpers. Access gates:login_requiredmiddleware and?next=round-trip helpers. - 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. - base36
- Base36 integer encoding — used in password reset
URLs and other URL-friendly opaque IDs.
int_to_base36(n)+base36_to_int(s)round-trip. Base36 integer encoding:int_to_base36/base36_to_int. - base62
- Base62 integer encoding — the
[0-9A-Za-z]alphabet, for short URL IDs. Like base36 but case-sensitive, so 6 bits per character. Base62 integer encoding:int_to_base62/base62_to_int. - body_
limit - Request body size limit middleware — fast
Content-Lengthrejection returning structured413 Payload Too LargeJSON. Replaces axum’s per-extractorDefaultBodyLimit. Seebody_limit::BodyLimitLayer. Request body size limit middleware. - bulk_
actions - Bulk-action runner — apply one operation to a set of selected PKs.
Works on all three backends. See
bulk_actions::BulkActionRegistryand the built-in actions. Pluggable bulk actions for the auto-admin — the “Action” dropdown above a list view. - cache
- Pluggable caching layer —
cache::Cachetrait +cache::NullCache+cache::InMemoryCache. Redis backend behind thecache-redisfeature. Pluggable caching layer. - cache_
fragment - Fragment caching — cache one rendered piece of a page.
cache_fragment::cached_renderchecks the cache before it calls your compute closure. It is a handler-side helper rather than a Tera block tag, because Tera has no block-tag extension API. Fragment caching: cache one rendered piece of a page. - cache_
page - Per-view caching tower layer +
Cache-Control/Varyheader builders. Caches a whole successful response and serves it again. Per-view caching: cache a whole successful response, plusCache-ControlandVaryheader builders. - casts
- Attribute casts —
Cast<C>field wrapper +CastValuetrait, with theEncryptedStringAEAD-at-rest built-in. Transform a field on its way to and from the database. - composite_
pk - Composite-primary-key patterns — a multi-column key expressed as an
Auto<i64>surrogate plusunique_together. Seecomposite_pk. How to model a key made of several columns — an order line identified by(order_id, line_no), say. - compression
- Response compression middleware — gzip and deflate. Honors
Accept-Encodingand skips bodies that are already compressed. Seecompression::CompressionLayer. Response compression middleware: gzip and deflate. - config
- Layered TOML configuration.
- content_
negotiation - HTTP content negotiation — pick the best response format from the
client’s
Acceptheader. Seecontent_negotiation::negotiate. Pick a response format from the client’sAcceptheader. - contenttypes
- ContentType framework — a runtime handle for “any registered model”. Used by permissions, generic foreign keys, soft-FK prefetch and audit-history admin panels. The ContentType framework.
- cookies
Set-Cookiebuilder —Cookie::new(name, value) .path("/").max_age(secs).http_only().secure().same_site(...).build()returns an axum-readyHeaderValue. Use it instead of writing cookie strings by hand. ASet-Cookiebuilder, plus a parser for aCookie:header.- 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 — makes a fresh random nonce per
request, exposes it as
Extension<Nonce>, and replaces'nonce-__RUSTANGO_NONCE__'in the CSP header, so inline<script nonce="...">tags pass a strict CSP. Seecsp_nonce::CspNonceLayer. Built withadmintoo:[security]mounts it so the bundled admin pages pass a strict CSP (#1703). Per-request CSP nonce middleware. - csv
- Minimal RFC 4180 CSV writer — zero deps. See
csv::CsvWriter. Small CSV writer. Follows RFC 4180 and pulls in no dependencies. - 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. A CSV download response. It setsContent-Typeand, when you give a filename, aContent-Dispositionthat makes the browser offer a “Save as” dialog. - databases
- Named multi-database registry +
QuerySet::using(alias). A registry of named databases, plusQuerySet::using(alias)to route a query to one of them. - dateformat
- Date format-character expander — turns a template format
string such as
{{ obj|date:"Y-m-d H:i" }}into the matching output. Template-style date format codes. - dateparse
- ISO 8601 date / time / datetime / duration parsers —
dateparse::{parse_date, parse_time, parse_datetime, parse_duration}. ISO 8601 / W3C date and time parsers. - dates
- Month / weekday name lookups —
month_full(m),month_abbr(m),month_ap(m),weekday_full(d),weekday_abbr(d). English-only by design (i18n is a separate concern). English month and weekday names. - dbshell
manage dbshell— spawnpsql/mysql/sqlite3for the currentDATABASE_URL.manage dbshell: open the native CLI client for the currentDATABASE_URL.- debug_
panel - Debug profiling panel at
/__debug__/— Telescope/Debug-Toolbar-shape. DEV ONLY — captures per-request telemetry. Seedebug_panel. Debug profiling panel —/__debug__/for development. - default_
filters - Everyday template filters —
pluralize,truncatewords,linebreaks,default_if_none. Seedefault_filters. Everyday template filters, registered on Tera. - distributed_
lock - Distributed locks backed by
cache::Cache— only one worker runs a task at a time. A TTL recovers the lock after a crash, and release is token-checked. 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 through the
crate::jobsqueue, so a temporary SMTP failure retries instead of failing the handler. 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 emails: joins thecrate::emailmailer to the Tera template engine. - env
- Typed environment variable readers —
required/with_default/optional/list/duration_secs/duration_millis. Typed readers for environment variables. - errors
- HTML error pages: the
errors::Messageextension, and (withtemplate_views) the layer that dresses 4xx/5xx responses. HTML error pages: one layer that dresses every 4xx/5xx of an app. - 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. - events
- Domain event bus — typed pub-sub for application events, separate from
the ORM. Use it for cross-component fan-out (
OrderPlaced→ mail + billing + audit). For per-model lifecycle hooks usesignalsinstead. Seeevents::EventBus. Domain event bus: typed pub-sub for application events, separate from the ORM. - extractors
- Per-request extractors for handlers — tenancy-aware DI. Ships
extractors::Tenant,extractors::SessionUser, andextractors::SessionOperator. Tenancy-aware extractors for handlers. - feature_
flags - Feature flags / killswitches backed by
cache::Cache— boolean killswitch + per-user override + stable percentage rollout. Seefeature_flags::FeatureFlags. Feature flags 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. - flatpages
- Static “flat pages” — about, terms, privacy. Build a
flatpages::FlatPageMap(path →flatpages::FlatPage) and mountflatpages::flatpages_middleware. A matching request serves the page body astext/html, or a content-type you choose. Tera wrapping is up to you. Static “flat pages” — about, terms, privacy. - 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. - host_
validation - Host-header allowlist middleware — refuses a request whose
Hostis not on the list. Seehost_validation::AllowedHostsLayer. Host-header allowlist middleware. - http_
client - Opinionated HTTP client —
reqwestwrapper with sane timeouts, retry on idempotent verbs / transient failures, default User-Agent. Seehttp_client::HttpClient. HTTP client: areqwestwrapper with sane timeouts, backoff retries and a defaultUser-Agent. - http_
date - HTTP date parser and formatter — reads RFC 1123, RFC 850
and asctime forms per RFC 7231; writes IMF-fixdate.
http_date::http_date(secs)+parse_http_date(s). HTTP date parser and formatter. - http_
methods - Per-route HTTP method allowlists as tower middleware —
require_GET,require_POST,require_safe. A method that is not allowed gets405 Method Not Allowedwith anAllow:header listing the rest. HTTP method restriction layer —require_methods,require_get,require_post,require_safe. - http_
query - HTTP
QUERYmethod routing (RFC 10008) —query(handler)and.query()chaining on axum’sMethodRouter. Seehttp_query::QueryRouterExt. Routing for the HTTPQUERYmethod (RFC 10008). - humanize
- Human-readable template filters —
intcomma,intword,naturalsize,ordinal,apnumber,naturaltime,naturalday. Seehumanize. Human-readable number, size and time filters for Tera. - 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, in the shape Stripe uses. - inheritance
- Model-inheritance patterns — how to share fields between models:
abstract bases, multi-table and proxy shapes. See
inheritance. Model-inheritance patterns: how to share fields and behaviour between models. - ip_
filter - IP allowlist / blocklist middleware. See
ip_filter::IpFilterLayer. IP allowlist / blocklist middleware — gate routes by client IP. - jobs
- Background job queue with a worker pool — async work outside the request
lifecycle. In-memory by default;
jobs-postgresadds the database-backed queue. Seejobs::JobQueue;jobs::Job::runsays which context each carries. Background job queue — async work outside the request lifecycle. - jsonapi
- JSON:API v1.1 response envelope — wrap a flat
serde_json::Value(typicalserializeroutput) in the{"data": {"type", "id", "attributes": {...}}}shape clients expect. Seejsonapi::to_resource+jsonapi::to_collection. JSON:API v1.1 response shape adapter. - jti_
store - Pluggable JTI revocation / single-use store. The default is in-memory;
implement
jti_store::JtiStoreto back it with Redis or a database when you run more than one instance. Pluggable JTI (JWT ID) revocation / single-use store. - 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. - list_
params - Shared list-endpoint query-parameter helpers — one place that owns the
reserved-key skip list,
?ordering=parsing and?page_size=clamping, soviewset::handle_listandtemplate_views::ListViewcannot drift apart. Query-parameter parsing shared by list endpoints. - livereload
- Browser auto-reload — refreshes pages when the server restarts.
DEV ONLY — pairs with
cargo watch -x run. Seelivereload. Browser auto-reload — refreshes the page when the server restarts. - logging
- One-call tracing-subscriber setup. See
logging::setup/logging::Setup. Tracing-subscriber setup in one call. - login_
field [auth] login_field: username or email for tenant sign-in. Which column a tenant user signs in with:[auth] login_field.- login_
throttle - Per-IP, per-account and global limits in front of every built-in
password login. See
login_throttle::LoginThrottle. One gate in front of every built-in password login. - lorem
- Lorem ipsum generators — placeholder text for demos, test
fixtures and template scaffolds.
lorem::words(n),lorem::paragraphs(n),lorem::sentence(). Lorem ipsum placeholder text. - mailable
- Laravel-shape
Mailabletrait — an email type as a struct that owns its template and recipient logic. Pairs withemail_templates::EmailRendererandemail_jobs. Seemailable::Mailable. TheMailabletrait: one email kind, one struct, owning its own template and recipients. It renders withcrate::email_templates::EmailRendererand can be queued throughcrate::email_jobs. - maintenance
- Maintenance-mode middleware — flip a shared flag and new requests get
503 with
Retry-After, while requests already running finish. Use it to drain traffic before a deploy or migration. Seemaintenance::MaintenanceFlag+maintenance::MaintenanceLayer. Maintenance-mode middleware: a shared flag turns every response into a 503 withRetry-After. Use it to drain traffic before a deploy or a migration without cutting off requests already running. - manage
- Unified manage runner — one
manage::Clibuilder in place ofsrc/main.rs+src/bin/manage.rsboilerplate. The tenancy variant appears with thetenancyfeature. Themanagefeature is on by default and pulls in a small axum + tokio surface, so bare-API projects can use the dispatcher withoutadmin. Unified manage runner — collapsessrc/main.rs+src/bin/manage.rsboilerplate into one builder so apps stop hand-writing the dispatcher. - manage_
interactive - Interactive prompts for
manageverbs —ask(prompt)reads a line andask_password(prompt)reads one without echoing. On non-TTY stdin both returnOk(None), so scripted callers still get the “missing required flag” error. Prompts for themanageCLI. - manager
- Custom Manager / QuerySet-extension pattern — give a model its own
named queries (
Post::published()) with a Rust extension trait. Seemanagerfor worked examples. How to attach your own query shortcuts to a model, so callers can writeArticle::objects().published()instead of repeating the same filter everywhere. - mcp
- Model Context Protocol (MCP) server — expose tools, prompts and
resources to external agents over JSON-RPC 2.0 and Streamable HTTP.
Mount with
mcp::router(single tenant) ormcp::tenant_router. A Model Context Protocol server, so an outside agent can use your app over JSON-RPC 2.0 and Streamable HTTP. - media
- First-class
Mediamodel — database-backed file references with direct-browser upload, CDN-aware URLs, soft delete and orphan purge. Seemedia::Media+media::MediaManager. First-classMediamodel — a real#[derive(Model)]row that references a file in thecrate::storage::Storagelayer. - messages
- Flash messages —
messages.success/info/warning/error/debugstored in a signed cookie until the next page renders them. Flash messages, backed by a signed cookie. - method_
override - HTTP method override — rewrite POST to PUT/PATCH/DELETE from the
X-HTTP-Method-Overrideheader or a_methodform field, so HTML forms can drive REST routes. Seemethod_override::MethodOverrideLayer. Method override: turn a POST into PUT, PATCH or DELETE from a hidden form field or a header. - metrics
- Prometheus-format metrics — counters + histograms exposed at
/metrics. Pure-Rust, no Prometheus client crate. Seemetrics::MetricsRegistry+metrics::metrics_router. Metrics in the Prometheus text format: counters and histograms, served 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. - numberformat
- Number formatter —
numberformat::format(value, decimal_sep, decimal_pos, grouping, thousand_sep). Thousands grouping, per-locale separators, optional fixed decimal width. Number formatting with explicit separators and grouping. - oauth2
- OAuth2 / OIDC social login. Works with plain OAuth2 providers (GitHub,
Discord) and OIDC ones (Google, Microsoft, Keycloak) through their
/userinfoendpoint. Per-tenant config viaoauth2::OAuth2Registry; the optional axum router isoauth2::router(needsadmin). 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). Build an OpenAPI spec, and optionally serve Swagger UI. - pagination
- Pagination helpers — RFC 5988 Link headers + cursor params.
See
pagination::LinkHeaderBuilder. Pagination helpers, in three shapes. - params
- Method-adaptive params extractor —
params::Paramsreads the query string on GET/HEAD and the body on QUERY, so one handler serves both. Method-adaptive params extractor: one handler servesGET /x?a=1andQUERY /xwith bodya=1. - passkey
- Passkey / WebAuthn — credential storage
(
passkey::WebauthnCredentialplus the store API) and the registration / assertion ceremonies, verified in pure Rust (CBOR + ES256). Passkey / WebAuthn support — issue #392. - password_
hashers - Pluggable
PASSWORD_HASHERSchain with upgrade-on-login. The firstpassword_hashers::PasswordHasherin the list writes new hashes, and every entry verifies its own format. A login that matches an older hasher returns a fresh hash, so you can store the upgrade. Pluggable password-hasher chain with upgrade-on-login. - password_
validators - Pluggable
AUTH_PASSWORD_VALIDATORSchain — run an ordered list ofpassword_validators::PasswordValidators at signup and password change. Built-ins:MinimumLengthValidator,MaximumLengthValidator,NumericPasswordValidator,UserAttributeSimilarityValidator,CommonPasswordValidator. Pluggable password validator chain. - passwords
- Generic password hash/verify + strength heuristic. See
passwords::hash. Generic password hashing + strength checking. - permissions
- Typed front end for the
tenancy::permissionsengine —has_perm_for_model::<T>/grant_role_perm_for_model::<T>/model_codenames_for::<T>. Ask for a permission by model type instead of typing the codename string. Needstenancy, which owns the tables. Permissions, reached by model type. - prelude
use rustango::prelude::*;brings the ORM’s extension traits into scope, soItem::objects().count(&pool)resolves without hunting them down.- 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”: error responses sent asapplication/problem+json. - prunable
- Model pruning — declarative bulk removal of stale rows. See
prunable::Prunable+register_prunable!. Model pruning: delete stale rows on a schedule. - query
- Query layer for rustango.
- random
- Random-string helpers —
get_random_string,get_random_token_urlsafe. CSPRNG-backed, so they suit session IDs, reset tokens and verification codes. Random strings —get_random_string/get_random_token_urlsafe. - 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 — a fixed-window counter over the
cache::Cachetrait. Pair it withRedisCacheto enforce one limit across several processes. Seerate_limit_cache::CacheRateLimitLayer. Distributed rate limiting via theCachetrait. - real_ip
- Real-IP extraction for apps behind a trusted reverse proxy. Reads
X-Forwarded-For,X-Real-IP,CF-Connecting-IPor RFC 7239Forwardedand puts the client IP in the request extensions. Seereal_ip::RealIpLayer. Real-IP extraction middleware for apps behind a trusted reverse proxy. - redirects
- Table-driven HTTP redirects. Build a
redirects::RedirectMapin code or from a CSV and mountredirects::redirects_middleware. A matching request returns 301/302 with the canonical URL inLocation, query string kept. Table-driven HTTP redirects for retired URLs. - request_
id - Request ID middleware — assign per-request correlation IDs,
honor a trusted proxy’s
X-Request-Idfor end-to-end propagation. Seerequest_id::RequestIdLayer. Request ID middleware: give every request a unique ID. - request_
timeout - Per-request handler timeout — stops a handler that runs too long and
returns
504 Gateway Timeout, so a stuck query or external call cannot pile up.Cli::with_settings_from_env()wires it fromSettings.server.request_timeout_secs. Seerequest_timeout::RequestTimeoutLayer. Cut off a request that runs too long. The handler is dropped and the client gets504 Gateway Timeoutinstead of a hung connection. - 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
- Serializer layer —
#[derive(Serializer)]+serializer::ModelSerializer. Typed JSON output from model instances with field control and validation. Serializers — typed JSON built from model instances. - server
- The development server.
server::Builderowns the boilerplate a tenancy app would otherwise rewrite: DB pool, resolver chain, host dispatch, operator console, bind and serve. - 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: show per-stage durations in the browser DevTools “Network → Timing” panel.- session
- Signed-cookie session primitives — an HMAC-SHA256 key wrapper and a
sign(secret, msg)helper, shared by every layer that sets a signed cookie so the crypto lives in one place. Seesession::SessionSecret.csrftoo: its cookie readssession::secure_cookies(#1608). Signed-cookie session primitives: the HMAC-SHA256 key wrapper plus the shared sign and verify helpers. - 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. - shortcuts
- Handler shortcuts —
get_object_or_404/get_list_or_404/render/redirect. Seeshortcuts. Handler shortcuts — the helpers every page render needs, so handlers do not reach for status codes, Tera and redirect builders by hand. - shutdown
- Graceful-shutdown signal handling — SIGINT and SIGTERM in one place,
so no serve path handles only half of them. See
shutdown::shutdown_signal. Graceful-shutdown signal handling. Every serve path uses this one function, so they cannot disagree. - signals
- Model lifecycle signals —
signals::connect_post_saveetc. Receivers register globally per model type and run sequentially. Model signals — hooks that run around a row write: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. - signing
- Value signer —
signing::Signer::sign(value)andsigning::TimestampSignerwith a TTL. Use it for signed payloads such as password reset tokens, magic links and signed cookies. Value signer. - sitemaps
- XML sitemap rendering. Write a
Sitemapimpl (or pass aVec<SitemapEntry>) and callsitemaps::render_sitemap. For large sites,sitemaps::render_sitemap_indexpoints crawlers at child sitemaps. XML sitemaps. - 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. A broadcast bus that sends one message to every subscriber. Use it for Server-Sent Events and other push patterns. - ssl_
redirect - HTTP → HTTPS redirect middleware, with exempt path prefixes and a
trusted proxy header. See
ssl_redirect::SslRedirectLayer. HTTP to HTTPS redirect middleware, with exempt path prefixes. - sso
- SSO (OpenID Connect / social OAuth) login core, independent of the
admin. Holds the shared handshake pieces (
ResolvedSso,build_provider,verified_email, …) and the DB-backedsso::SsoProvidermodel. The admin, the tenant console and member auth all build on it; theadmin-ssofeature adds the admin login wiring. SSO (OpenID Connect / social OAuth) login — the admin-INDEPENDENTssofeature. - 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 send them withContent-Type,Cache-ControlandLast-Modified, and answer 304 toIf-Modified-Since. - storage
- File storage backends —
storage::Storagetrait + LocalStorage + InMemoryStorage. File storage: save, read and delete files through one trait, with a backend you choose. - syndication
- RSS 2.0 and Atom 1.0 feed rendering.
Build a
syndication::Feedwith channel metadata andsyndication::FeedItems, then callsyndication::render_rssorsyndication::render_atom. RSS 2.0 and Atom 1.0 feeds. - task_
context - Context that follows work off the request thread — see
task_context::TaskContext.tokio::spawninherits notask_local!, so deferred work starts with none of its caller’s ambient context unless it is carried deliberately. Context that follows work off the request thread. - template_
context_ processors - Sitewide template context processors — see
template_context_processors. Template context processors. - template_
debug - DEBUG template-error overlay — see
template_debug. Template error page for development. - template_
extensions - Custom template filters and functions — see
template_extensions. Custom template filters and functions. - template_
views - Generic class-based views for HTML templates —
ListView,DetailView,CreateView,UpdateView,DeleteViewover#[derive(Model)]schemas, rendered with Tera. The HTML sibling ofviewset. Runs on all three backends. Seetemplate_viewsfor usage and the Tera context shape. Generic class-based views for HTML templates. - tenancy
- Multi-tenancy for rustango.
- tenant_
log - Ambient tenant identity for log lines — the per-request slot the
resolver fills and the access log reads back. Without a resolver the
slot stays empty and no tenant is logged. See
tenant_log::record/tenant_log::current. Tenant identity for log lines: the field that says whose request this was. - test_
assertions - Test assertion helpers —
assert_contains/assert_redirects/assert_status/assert_messagesover axum responses. Thequery_countersubmodule is ORM instrumentation thatsql::executorbumps on every query, so the module is always compiled and the response assertions carry their own_axumgate. Assertion helpers for axum responses. - 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. - test_
data - Shared test fixtures — the
setup_test_data!/setup_test_data_async!macros build the fixture once per process (per file undercargo test, per test under nextest). Shared test fixtures, built once per test process. - test_db
- Test-time DB isolation.
test_db::with_rollbackruns an async closure in a transaction that always rolls back, so one test’s writes never reach the next. Database isolation for tests, in four tiers. - test_
factory - Test factories — build model instances for tests without repeating
struct literals. A
test_factory::Sequencecounter plus thetest_factory::Factorytrait withbuild_batch. Test fixture builders, in the style offactory_boy. - test_
filter - Tag-based test filtering — label a test and run a subset with
manage test --tag fast --exclude-tag slow. Puttags!("slow")at the top of a#[test]body and it skips itself whenRUSTANGO_TEST_TAGS/RUSTANGO_TEST_EXCLUDE_TAGSfilter it out. Run tests by tag — label a testsloworcoreand filter on it. - test_
server - Live HTTP server for tests. Binds an
axum::Routerto a random localhost port on a background task. Use it when in-processtest_client::TestClientrouting is not enough, for example with Selenium, websockets, or code that reads the host header. A real HTTP server for tests, on a real port. - test_
settings - Test-only Settings overlay — installs a
per-task
config::Settingsoverlay, so tests change configuration without touching process-global state.Settings::load/load_from_envreturn the overlay while it is active. OverrideSettingsfor the span of one test. - testkit
- Test-support helpers (schema builders from
Model::SCHEMA+ model factories). Dev-only:#[cfg(test)]for this crate’s own tests,feature = "testkit"for external integration tests. Test-support helpers: build the framework’s own tables from each model’sSCHEMA— never hand-written DDL — and construct fully-populated framework model instances via factories. - text
- Text utilities — slugify, html_escape, truncate. Text utilities — slug generation, HTML escaping, truncation.
- timesince
- Elapsed-time wording —
timesince/timeuntil, with adepthcontrol (“4 days, 6 hours”). The Tera filter wrappers live inhumanize. Human-readable durations: “4 days, 6 hours”. - 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 OpenTelemetry field names andtraceparentheader propagation. Addtracing_opentelemetry::layer()to your subscriber to get distributed tracing. Seetracing_layer::TracingLayer. Per-requesttracingspan with W3C / OpenTelemetry-conventional field names +traceparentheader propagation. - trailing_
slash - Trailing-slash redirect middleware — canonicalize URL paths so
/postsand/posts/do not split your traffic. Seetrailing_slash::TrailingSlashLayer. Trailing-slash redirect middleware: one canonical form per URL. - uploads
- Multipart file upload helper — wraps axum’s multipart extractor +
the
storage::Storagetrait. Seeuploads::save_uploads+uploads::UploadConfig. Multipart file uploads. Joins axum’s multipart extractor to thecrate::storage::Storagetrait, and handles size limits, extension checks and filename sanitizing for you. - url_
codec - URL / IRI / URI helpers —
url_encode,uri_to_iri,iri_to_uri,escape_uri_path,filepath_to_uri,urlsafe_base64_encode/_decodeand friends. Purestd, so it is always compiled. URL codec helpers:application/x-www-form-urlencodeddecoding, RFC 3986 percent encoding, and urlsafe base64. - urls
- Named URL reversal — build a URL from a route name and its params,
instead of formatting paths by hand. Pair with
register_url!. Named URL reversal — build a URL from a route name and its params. - validators
- Standalone validators —
validate_email,validate_url,validate_slug,validate_min_length/validate_max_length,validate_min_value/validate_max_value. Seevalidators. Standalone validators. - viewset
- ModelViewSet — five REST endpoints for any
Modeltable in about five lines. Runs on all three backends, including the.serializer()render extension. Seeviewset::ViewSet. - webhook
- Webhook signature verification (HMAC-SHA256). See
webhook::verify_signature. Webhook signature checks, using HMAC and constant-time compare. - webhook_
delivery - Outbound webhook delivery — POSTs HMAC-signed JSON through the
background job queue, so retries with backoff come for free. See
webhook_delivery::WebhookSubscription. Outbound webhooks: POST an HMAC-signed JSON payload to a subscriber URL through 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. It shows 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 built on the SSEEventBus.
Macros§
- Q
Q!()— compact filter syntax compile-time-resolved against typed columns. Each invocation expands to the equivalent typed-column method call, so field-name typos fail the build. Seerustango_macros::Qfor the supported lookup suffixes.- atomic
- Sugar over
atomicthat wraps the body inBox::pin(async move { … })so callers don’t have to. Identical semantics: - by_
dialect - Pick a value per backend, with every backend spelled out.
- 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. - register_
admin_ computed - Register an admin computed field. Pair with a
#[derive(Model)]type whoseadmin(list_display = "…")names this field. - register_
admin_ inline - Register an admin inline. The
parent/childarguments must match theModelSchema::tableof two#[derive(Model)]types already in the registry. - register_
admin_ inline_ generic - Register a generic admin inline. Same shape as
register_admin_inline!but takesct+pkinstead offk. - register_
admin_ list_ filter - Register a custom list filter on the table whose list view should show the filter card.
- register_
admin_ object_ permission - Register a permission predicate for one model.
- register_
admin_ queryset - Register an admin queryset hook for one model.
- register_
admin_ superuser_ fields - Mark fields of one model superuser-only for an admin write. The model, action and field names are checked at compile time, so call it where the fields are visible.
- register_
admin_ view - Register a custom admin view for one model.
- register_
command - Register a
managecommand from any crate, without the host app changingmain. The handler gets aCommandContextand the arguments after the verb (--tenant <slug>already taken out). A name that clashes with a built-in verb or another command makesCli::runfail at startup. - register_
mcp_ resource - Register a resource that every authenticated agent can read, with no skill grant needed.
- register_
mcp_ tool - Register a tool at compile time.
- register_
migration_ callback - Register a named migration callback. Pair the chosen name with a
{"callback": {"name": "..."}}entry in your migration JSON’sforwardarray. - register_
prunable - Register a
Prunableimpl somanage prune,prune_allandprune_pretendcan find it. Pass the model type only; the name comes from its table. - register_
template_ context_ processor - Register a context processor.
apply_to_contextruns it. - register_
template_ filter - Register a Tera filter.
apply_to_terainstalls it. - register_
template_ function - Register a Tera function.
apply_to_terainstalls it. - register_
url - Register a named URL pattern at startup. Uses
rustango::inventory, so you do not need your own dependency on it. - setup_
test_ data - A shared fixture built by sync code. Wraps a
std::sync::OnceLock. - setup_
test_ data_ async - A shared fixture built by async code, such as one that inserts
rows. Wraps a
tokio::sync::OnceCell, so concurrent first callers all wait on one run of the body. - tags
- Declare this test’s tags and return early if the env vars filter it out. Put it at the top of the test body, before any setup.
- tri_
dialect_ test - Fan a list of scenario functions out into one
#[tokio::test]per backend. - with_
rollback with_rollbackwith theBox::pin(async move { … })wrapper written for you. Behaves the same:- with_
truncate_ after with_truncate_afterin the same macro shape aswith_rollback!:
Enums§
- Rustango
Error - One error type for app code. Every framework error has a
Fromimpl into it, so?works in a handler.
Functions§
- server_
error - A logged
500that withholds the cause, for handlers that return(StatusCode, String):.map_err(rustango::server_error)?(#2032).
Type Aliases§
- Rustango
Result ResultwithRustangoErroras the error type.
Attribute Macros§
- main
#[rustango::main]— the application entrypoint. Wraps#[tokio::main]and bootstracing-subscriberfromRUST_LOG, falling back toinfo,sqlx=warn.RUSTANGO__LOGGING__FORMAT=jsonlogs JSON.#[rustango::main]— the runserver entrypoint. Wraps#[tokio::main]and a defaulttracing_subscriberinitialisation (env-filter, falling back toinfo,sqlx=warn) so usermainfunctions are zero-boilerplate.RUST_LOGandRUSTANGO__LOGGING__FORMAT(e.g.json) come from the real environment, else from./.env(only those keys are read):
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::Form(slice 8.4B). Generates aparse(&HashMap<String, String>) -> Result<Self, FormErrors>impl that walks every named field and:- Model
#[derive(Model)]— populates theinventoryregistry the admin walks, generatesobjects()/ typed columns /insert/delete/save.- Serializer
#[derive(Serializer)]— implementsserializer::ModelSerializeron a struct, generatingfrom_model, a customserde::Serialize(respectingwrite_only), andwritable_fields. Re-exported when theserializerfeature is on. Deriverustango::serializer::ModelSerializerfor a struct. (intra-doc link disabled — the macro crate doesn’t depend onrustangoitself, so rustdoc can’t resolve the path.)- ViewSet
#[derive(ViewSet)]— generates arouter(prefix, pool) -> axum::Routerassociated method on a marker struct, wiring the full CRUD ViewSet in one annotation. Re-exported underadminortenancy(the generatedrouter(...)expands to__axum::Router, whichadminprovides); the generatedrouter(...)works without tenancy, andtenant_router(...)adds the multi-tenant path whentenancyis also enabled. Derive arouter(prefix, pool) -> axum::Routerassociated method on a marker struct, wiring the full CRUD ViewSet in one annotation.