You've shipped Rust services on Axum, Actix, Rocket, or hand-rolled hyper. You know the language and the runtime. What does Suprnova actually buy you?
The productivity layer. Routing, controllers, an ORM, migrations, queues, scheduling, auth, mail, notifications, broadcasting, cache, storage, validation, and a typed frontend bridge - all wired together, all using the same conventions, all production-ready. You write controllers and models; you don't pick the layout.
If you've already built one or two real apps in Axum, you know how much of that effort was wiring rather than features. Suprnova is the wiring, done once, opinionated where opinion matters, pluggable where it doesn't.
The 30-second TL;DR
You now have:
- A hyper server with HTTP/1.1 and HTTP/2, WebSocket upgrade, graceful shutdown
- A SeaORM-backed Eloquent layer with relations, eager loading, soft deletes
- Inertia.js bridging Rust → Svelte 5 with typed
#[derive(InertiaProps)] - Auth (sessions, password hashing, provider-backed email verification + password reset, plus 2FA and OAuth via torii)
- A queue with memory/sync/redis/database/null drivers
- A cron scheduler driven by the
Tasktrait - A console binary per project for
cargo run --bin console <cmd> - Cache, storage (fs/s3/azblob/gcs), mail (SMTP + 5 providers: SES, Mailgun, Postmark, SendGrid, Resend), web push
- Broadcasting over a pluggable hub (sea-streamer by default)
- Validation, CSRF, CORS, rate limiting, idempotency, request timeouts, structured errors
And one statically linked binary at the end of cargo build --release.
What's underneath
| Concern | Crate |
|---|---|
| HTTP server | hyper + tower-ish middleware (own implementation) |
| Async runtime | tokio |
| Router | matchit |
| ORM | sea-orm (re-exported as suprnova::sea_orm) |
| Migrations | sea-orm-migration |
| Database drivers | sqlx (postgres / mysql / mariadb / sqlite) |
| Serialization | serde / serde_json |
| Validation | validator |
| Sessions | own (driver-based) |
| Templating | tera (for mail bodies; frontend is Inertia) |
| Crypto | aes-gcm, argon2, bcrypt |
| WebSockets | hyper-tungstenite |
| Streaming | sea-streamer (broadcasting fanout backend) |
| OAuth | torii (vendored fork) |
| Tracing | tracing + tracing-subscriber |
You won't typically reach for any of these directly - Suprnova
re-exports what you need. SeaORM is the deepest passthrough: Entity,
Column, ActiveModel, ConnectionTrait, the query builder, the
migration prelude. The escape hatch is use suprnova::sea_orm; if you
need something the curated surface doesn't cover.
What Suprnova adds over raw Axum
Axum is excellent. So is Actix. So is Rocket. The reason Suprnova exists isn't that those frameworks are bad - it's that every team building a real product on them ends up re-implementing the same productivity layer. Suprnova ships that layer:
| Capability | Hand-roll on Axum | In Suprnova |
|---|---|---|
| Routing macros that scale to hundreds of routes | Builder API, can get noisy | routes! macro with grouping, prefixes, middleware, naming |
| Route model binding (path id → loaded model) | Custom extractor per type | #[handler] resolves post::Model from {id} automatically |
| Eloquent-style chainable query builder | Use SeaORM directly | Post::query().db_where(...).order_by(...).get().await? |
| Soft deletes, observers, lifecycle events | Build per-model | #[model(soft_deletes)] + impl Observer<Post> |
| Migrations + entity generation | Wire sea-orm-cli + scripts | suprnova db:sync runs migrations and regenerates entities |
| Auth (sessions, providers, guards) | Stitch tower-sessions + own logic | Auth::attempt, Auth::user, .middleware(AuthMiddleware) per route |
| Email verification, password reset, 2FA, brute-force | Hand-build all four | All built in, configurable, idempotent |
| Background queue | Pick a driver, write workers | Queue::push + cargo run -- queue:work |
| Cron scheduling | Write a tokio task with tokio_cron_scheduler |
impl Task + Schedule::task(...).daily().at("03:00") |
| Inertia bridge | Build extractors + a JS adapter | inertia_response!(&req, "Page", props) |
| Typed frontend props (Rust → TS) | Write a generator | #[derive(InertiaProps)] + suprnova generate-types |
| Broadcasting (public / private / presence channels) | Wire a streaming backend + auth | BroadcastHub + Channel/PrivateChannel/PresenceChannel traits |
| Mail with multiple providers | Pick one, write your own abstraction | Mail::driver("ses") etc., uniform Mailable API |
| WebPush | Read the spec, build a notifier | WebPushChannel ships, VAPID baked in |
| Validation + form requests | Use validator + custom extractor |
#[derive(Data, Validate)] form requests, async validation |
| JSON:API resources | Hand-format responses | #[derive(Resource)] |
| Rate limiting with fail-open/closed policy | Build it | RateLimiter + BackendErrorPolicy |
| Idempotency keys | Build it | Idempotency::remember(key, ttl, body) with Stripe-style replay |
| CSRF (with Laravel-style glob exclusions) | Build it | CsrfMiddleware with except + except_method |
| Structured errors with sanitised 5xx | Build it | FrameworkError / HttpError trait, panic recovery |
| Container with task-local → thread-local → global scopes | Write your own | App::bind / singleton / factory with proper isolation |
| Health endpoint, request id, structured logging | Glue together | All on by default |
The trade-off is opinions: Suprnova picks a layout, picks a default driver, picks a naming convention. You can deviate (drivers are pluggable, config is overridable, the container lets you swap services), but the defaults are designed to be the right choice for "build a product quickly".
Familiar Rust patterns
You'll recognise the shapes:
// A handler returns `Result<HttpResponse, HttpResponse>` (aliased Response).
pub async
// Middleware is a trait, not a closure:
// Background work is the `Job` trait - `handle(self)` runs the job:
If you're used to Tower middleware: Suprnova middleware is conceptually
the same (a wrapper around next), but uses an own trait (not Tower's
Service) because tower's combinator types get nasty when you start
nesting application-specific extractors. The shape is simpler; the
mental model is the same.
If you've used Axum's extractor pattern: Suprnova's #[handler] macro
plays the same role, but resolves through the service container rather
than via traits, which lets it inject app services as well as request
data. Route model binding (Post from {id}) is built in.
If you've used sqlx directly: Suprnova's ORM sits over SeaORM, which
sits over sqlx. You can drop to raw SQL via DB::select(...) /
DB::select_one(...) or use DB::table("name") for chainable dynamic
queries; you can drop straight to SeaORM for things the Eloquent
surface doesn't cover (e.g. raw Statement queries with custom result
mapping). The Eloquent chapter covers the escape hatches.
What's the productivity delta?
Pick a feature you've built before in raw Axum. Suprnova ships it as a chapter:
- "I built an auth system once and it took two weeks." → Authentication + Auth Flows. Set the migration, configure the guard, you're done.
- "I wrote my own queue worker with retry/backoff." →
Queues.
Queue::push+cargo run -- queue:work. - "I wired WebSockets with hyper-tungstenite once." →
WebSockets. The
ws!()macro types the handler; the upgrade, ping/pong heartbeat, close-frame handshake, and back-pressure are taken care of. - "I built an Inertia adapter from scratch." →
Inertia.
inertia_response!(&req, "Page", props), withInertiaPropsgenerating the TS types. - "I built a per-tenant rate limiter." → Rate Limiting. Configurable key, configurable fail-open vs fail-closed policy, fail-closed returns 503.
- "I implemented Stripe webhook signature verification + replay protection." → Payments: Stripe. Built into the adapter, webhooks go into a mirror table with UNIQUE idempotency.
What you'd build by hand in two weeks, you import in one line.
What you'll still recognise as "yours"
A few things stay close to raw Rust because the language gives you something better than a framework abstraction:
- Concurrency primitives.
tokio::spawn,Arc,Mutex, channels - use them. The framework doesn't wrap them. - Error types. You define your domain errors. Implement the
HttpErrortrait on them to get a proper status code + message in the wire response. The framework'sFrameworkErrorandAppErrorare escape hatches for cross-cutting + ad-hoc errors respectively. - Custom drivers. Cache, queue, mail, broadcasting, vector, payments -
every "driver registry" subsystem accepts custom drivers. Implement
the trait, register it in
bootstrap.rs, done. - Raw SQL when you want it.
DB::select(...),DB::table(...).get()for dynamic rows, or drop fully to SeaORM. The ORM gets out of the way. - Your own tower middleware? Suprnova doesn't ship a Tower
adapter - middleware here is
impl Middleware, nottower::Service. If you need to bring a Tower-only crate, you'd adapt it by hand. In practice, the built-in middleware system covers almost everything you'd reach for. See Middleware.
What you give up
Honesty matters more than marketing:
- Conventions. Models live here, controllers there, migrations there, observers there. The scaffolder picks. You can fight it; you probably shouldn't. The conventions are Laravel's, audited and battle-tested.
- Some flexibility in how the request flows. The middleware chain has a fixed outermost order (request-id → globals → route middleware → handler). You can insert middleware anywhere in that, but you can't move the request-id or panic-recovery layers - they're invariants.
- The PHP-shaped corners. Where Laravel does something because PHP, Suprnova does the Rust-shaped thing instead - but we tell you when. Look for "Why Suprnova diverges" callouts in chapters.
Why "Laravel-inspired" should matter to you even if you've never written PHP
The Rust web ecosystem is roughly where the PHP one was around 2009. The crates exist; the patterns don't. Suprnova ports an extremely refined set of patterns from a framework that has had 10+ years of production pressure shaping it. You get patterns that already survived contact with reality.
The cost is that Suprnova is opinionated. If you want a minimal "pick-your-own-everything" framework, Axum is right there and it's excellent. If you want a "framework that decides things so you can focus on the product", that's Suprnova.
Next steps
- Installation -
suprnova new, what gets scaffolded - Quickstart - build a tiny app in 5 minutes
- Request Lifecycle - how a request flows, what runs where
- Service Container - how services are bound and resolved
- Eloquent - the longest chapter; the surface is wide
Or jump anywhere via documentation.md.
