Skip to content

Repository files navigation

Suprnova

A Laravel-inspired web framework for Rust.

License: MIT CHANGELOG

Suprnova - A Laravel-inspired web framework for Rust

Suprnova is a full-stack Rust web framework with Laravel 13's developer experience and Tokio's runtime model. Familiar API surfaces - Auth::login, Cache::remember, Mail::to, Event::dispatch, Eloquent-style models, #[handler], #[command], routes! - sit on top of a hyper / SeaORM / async-trait stack designed for long-lived connections, in-process workers, and concurrent IO. No request-per-process compromise.

Current main requires Rust 1.94.0 or newer. The tagged v2.0.2 release has the same Rust 1.94.0 floor.

cargo install --git https://github.com/eas4ai/suprnova.git --tag v2.0.2 suprnova-cli
suprnova new myapp --frontend svelte
cd myapp
suprnova serve

Your app is now serving at http://localhost:8765, with a Vite dev server proxied for the frontend.

Quick taste

If you've used Laravel, this should feel like home - only typed.

use std::time::Duration;
use suprnova::{handler, routes, attrs, inertia_response, json_response, Response};
use suprnova::{Auth, Cache, Event, RouteParam};
use crate::models::Post;
use crate::events::PostCreated;
use crate::requests::CreatePostRequest;

routes! {
    get!("/",             home),
    get!("/posts/{post}", show),
    post!("/posts",       store).middleware(Authenticate),
}

#[handler]
async fn home() -> Response {
    let popular = Cache::remember(
        "posts.popular",
        Some(Duration::from_secs(60)),
        || async { Post::query().db_where_op("views", ">", 1000).get().await },
    )
    .await?;
    Ok(inertia_response!("Home", { "posts": popular }))
}

#[handler]
async fn show(RouteParam(post): RouteParam<Post>) -> Response {
    Ok(json_response!({ "post": post }))
}

#[handler]
async fn store(req: CreatePostRequest) -> Response {
    let post = Post::create(attrs! {
        user_id: Auth::id().ok_or_else(|| FrameworkError::Unauthorized)?,
        title:   req.title,
        body:    req.body,
    })
    .await?;
    Event::dispatch(PostCreated { post: post.clone() }).await?;
    Ok(inertia_response!("Posts/Created", { "post": post }))
}

RouteParam<Post> applies the model's global scopes and soft-delete filter automatically. Post::query() is the Eloquent builder (db_where_op is the Laravel-side alias of filter_op for arbitrary SQL operators). The #[handler] macro pulls FormRequests out of the body, route params out of the URI, and authenticated users out of the session - all type-checked.

What's in the box

The Laravel-13 parity surface plus the Rust-native wins:

Layer What ships
HTTP & routing Router, named routes, route groups & prefixes, parameter binding, resource routing, signed URLs, redirect helpers (Redirect::to/back/route/with_errors/…), #[handler] macro, 100% type-checked
Middleware CORS, CSRF, session, request-timeout, request-id, throttle / login-throttle, signed-URL verify, authenticated, email-verified, brute-force, custom global/group/per-route
Inertia 3 bridge InertiaProps derive + TypeScript codegen, partial reloads, deferred / lazy props, version mismatch handling, SSR loopback, #[handler] integration, three starters: Svelte 5 / React 19 / Vue 3.5
Eloquent ORM #[suprnova::model] macro, 11 relation kinds (hasMany / belongsToMany / morph / polymorphic / through), eager loading, soft deletes, observers, global & local scopes, casts, 16 lifecycle events, factories + seeders, Collection<M>, 3 paginators, chunk/lazy/cursor iteration, multi-connection R/W split, transactions + savepoints + retry-on-deadlock
Auth Auth::user/login/once/check, named guards via AuthManager, remember-me, 2FA TOTP with recovery codes, email verification, password reset, brute-force lockout, login throttle, role/permission gates, #[policy] registration
Database SeaORM-backed migrations + entity codegen, four databases: SQLite / Postgres / MySQL / MariaDB (MariaDB rides the MySQL driver and adds a native vector driver), DB::transaction with savepoints, query logging, multi-connection registry
Cache Memory, file, Redis - Cache::remember + lock-based Cache::lock + tags + atomic Redis Retry-After
Queues & jobs Memory, sync, Redis, database - queue routing (Queue::route, Job::queue, queue:work --queue=billing), middleware pipeline, batches, chains, retry schedules, failed-job store, unique jobs
Events & bus Event::dispatch, Listener/Subscriber, queued listeners, panic-isolated dispatcher, command/query bus
Notifications Mail / database / broadcast / Web Push channels, anonymous notifications, deferred dispatch
Mail SMTP, Mailgun, Postmark, SendGrid, Resend, SES, log + in-memory transports, Markdown templates via Tera, fake() helper, queued mail
Broadcasting & WebSocket Channels (public / private / presence), BroadcastHub trait, sea-streamer fanout adapter, JSON-envelope protocol, supervised heartbeats with auto-restart
Filesystem Local + S3 (R2 / B2 / MinIO compatible) via OpenDAL, path-traversal guard, atomic copy
Vector Memory, Qdrant, Pinecone, MariaDB native VECTOR(N) (HNSW + cosine/euclid/L1/L2) - first-class trait + drivers, no Postgres-only gatekeeping
Payments Generic Payment / Subscription / CustomerStore / WebhookHandler traits + DB mirror; Stripe and Paddle reference adapters; webhook UNIQUE idempotency
Validation Required, Email, Min/Max/Between, RequiredIf/With/WithAll/Unless, Unique (async), Confirmed, custom rules via traits, validator derive integration
Scheduling Schedule::call / command / job, cron expressions, runInBackground, withoutOverlapping, supervised execution
Workflows Durable steps via #[workflow_step], #[workflow] orchestration, panic-recovery on the queue, exponential backoff with strict caps
Console Per-project console binary (the Rust analogue of php artisan), #[command] + #[derive(Command)] typed args, make:* generators, db:seed
Observability Structured tracing everywhere, request IDs end-to-end, OpenTelemetry support, DB query logging via QueryExecuted events
Testing #[suprnova_test], in-memory SQLite via TestDatabase, fakes (Mail::fake(), Queue::fake(), Event::fake(), BroadcastHub recorder), expect! macro, handle_request in-process driver
Feature flags DatabaseEvaluator + CachedEvaluator + admin CRUD + sub-second propagation via FeatureSync
Idempotency, rate-limit, CORS, CSRF, sessions, hashing, crypto First-class; each subsystem ships fail-open vs fail-closed as an explicit policy choice

Starter kits

Don't start from an empty scaffold (unless you want to o_O) - fork a kit:

  • Nebula - authentication (Breeze-tier): register, email verification, login with remember-me, password reset, and profile management, on Inertia 3 + Svelte 5.
  • Pulsar - a full product site and community on Vue 3.5 + Vuetify: everything in Nebula plus a marketing landing, dashboard, a Markdown docs pipeline, a blog with RSS, member profiles, taxonomy, role-based access control, and admin/moderation surfaces.
  • Directory starter - listings, moderation, and paid publication on Vue 3.5: owners submit listings, moderators review them, visitors search them, and publication is free or paid through Stripe and Paddle.

See Starter Kits for the full rundown, or run suprnova new for the plain scaffold on any of the three frontends.

End-to-end type safety

Define props in Rust once; use them in TypeScript with full autocomplete.

use suprnova::{handler, InertiaProps, inertia_response, Response};

#[derive(InertiaProps)]
pub struct HomeProps {
    pub title: String,
    pub user: UserDto,
}

#[derive(InertiaProps)]
pub struct UserDto {
    pub name: String,
    pub email: String,
}

#[handler]
pub async fn index() -> Response {
    Ok(inertia_response!("Home", HomeProps {
        title: "Welcome!".into(),
        user: UserDto {
            name: "Ada".into(),
            email: "ada@example.com".into(),
        },
    }))
}

Run suprnova generate-types and your frontend/src/types/inertia-props.ts mirrors the Rust shape exactly. Change a field, regenerate, the compiler points at every component that needs to update.

Durable workflows

Workflow steps survive process restarts and retry with exponential backoff

  • jitter (strict cap, no doubling past it):
use suprnova::{workflow, workflow_step, start_workflow, FrameworkError};

#[workflow_step]
async fn fetch_user(user_id: i64) -> Result<String, FrameworkError> { ... }

#[workflow_step]
async fn send_welcome_email(user: String) -> Result<(), FrameworkError> { ... }

#[workflow]
async fn welcome_flow(user_id: i64) -> Result<(), FrameworkError> {
    let user = fetch_user(user_id).await?;
    send_welcome_email(user).await?;
    Ok(())
}

// Enqueue & run the worker:
let handle = start_workflow!(welcome_flow, 123).await?;
suprnova workflow:work

Documentation

  • Manual - 100+ chapters, every public subsystem. Pick a reading path: From Laravel (if you know Auth::user() / Eloquent / Blade) or From Rust Web (if you know Axum / Actix / Rocket).
  • Quickstart - small app end-to-end.
  • CHANGELOG.md - keep-a-changelog format.
  • Introduction - the design principles the framework is built on, including why every backend-bearing subsystem is a trait with drivers rather than one blessed implementation.
  • Contributing - the working agreement: full implementations only, well tested, production-ready. A feature ships when it's done, not when it has a prototype.

Distribution model

Suprnova distributes via git, not crates.io. Generated apps depend on suprnova = { git = "https://github.com/eas4ai/suprnova.git", tag = "v2.0.2" }; the CLI installs via cargo install --git. Adapter crates (suprnova-payments-stripe, suprnova-payments-paddle, suprnova-web-push) follow the same model. The tag is the release: an app moves versions by editing one tag = line, each version's CHANGELOG section is its release record, and as of v1.0.0 breaking changes land only behind a version bump that says so.

License

MIT, © 2026 Shawn McAllister & Dayem Siddiqui - see LICENSE. Suprnova began as a fork of Kit (MIT, © Dayem Siddiqui) and has since been taken in its own direction.