● Open source · MIT / Apache-2.0 · Rust 1.94+
Laravel's productivity.
Rust's guarantees.
Renox is a batteries-included web framework for Rust. Routing, models, migrations, validation, auth, queues, mail, a UI kit and more, behind one dependency, compiled into one binary.
cargo install renox-cli
❯ cargo install renox-cli Installed rnx v1.1.1 ❯ rnx new shop created Cargo.toml created src/lib.rs created src/app/home/mod.rs created resources/views/layouts/app.html created migrations/ created tests/home.rs created AGENTS.md ❯ cd shop && rnx serve Compiling shop v0.1.0 migrated 9 tables ▲ Renox listening on http://127.0.0.1:3000
1,608tests
90%line coverage, enforced
72UI kit components
130demo pages explained beside their code
6official plugins
27built-in commands
001 The problem
A Rust web app today is twenty crates and a week of glue.
Rust gives you speed and a compiler that catches bugs before your users do. But for a web app you pick a router, an ORM, a session store, CSRF protection, a queue, a mailer, templates and migrations, then wire them together and keep them in step. Laravel solved that years ago, without Rust's guarantees. Renox brings that productivity to Rust.
- One dependency.
renox = "1"anduse renox::prelude::*: everything else is already there, and already fits. - Laravel's ideas, Rust's types. Routes, models, form requests, jobs, mailables and policies: names you know, checked at compile time. Laravel → Renox, concept by concept.
- Upgrades are a version bump. Apps depend on Renox; framework code is never copied into them.
- axum
- tower
- sqlx
- tokio
- minijinja
- serde
- validator
- argon2
- lettre
- cookie
- tower-sessions
- apalis
- cron
- tracing
- reqwest
- object_store
- chrono
- uuid
- csrf
- governor
- rust-embed
- clap
renox = "1.1"all of it, in one crate
002 Batteries included
Everything a real app needs. Already wired.
Not a starter template: a framework you depend on, tested as one piece on SQLite and PostgreSQL, on Linux, macOS and Windows.
- 001
Routing & requests
Named routes, groups, domains, guards, rate limits, signed URLs, route model binding.
Routes::new().get("/", home)Read the routing & requests guide → - 002
Models & migrations
A query builder that checks column names, relations without N+1, migrations with batches, SQLite or PostgreSQL.
#[derive(Model)]Read the models & migrations guide → - 003
Validation
Form requests as structs with Laravel's rules, hooks, live validation, errors placed next to the field.
Valid<NewOrder>Read the validation guide → - 004
Auth & permissions
Login, registration, reset, verification, API tokens, roles per tenant, policies, two-factor login, OAuth.
.require_permission("orders.refund")Read the auth & permissions guide → - 005
Queues & scheduler
Jobs with retries, chains and batches; a cron scheduler that is safe across servers. No Redis needed.
state.queue.dispatch(SendInvoice { … })Read the queues & scheduler guide → - 006
Mail & notifications
SMTP with failover, mail views, notifications by mail, in the database and as a live stream.
state.notify(user, &OrderShipped { … })Read the mail & notifications guide → - 007
UI kit, grid & HTMX
72 accessible components, 112 icons, an editorial theme, a data grid with exports, and renox-blocks; htmx and Alpine.js built in.
{{ grid(orders) }}Read the ui kit, grid & htmx guide → - 008
One-binary deploys
Views, translations, migrations and assets compiled in; systemd socket activation, so restarts refuse no connection.
rnx buildRead the one-binary deploys guide →
003 Under the hood
Every request goes through a pipeline you don't have to build.
Security headers, sessions, CSRF, auth and error pages are on from the first line. Hover a layer to see what it does.
The request arrives
Axum and Tokio underneath: async, on every core, nothing to install next to the binary.
GET /orders/42 HTTP/1.1 Host: shop.example.com Cookie: renox_session=…Security headers & CSP
nosniff, frame options, HSTS and a Content-Security-Policy with a nonce per request, on every response. Trusted hosts and proxies too.
content-security-policy: default-src 'self'; script-src 'self' 'nonce-r4Nd0m' strict-transport-security: max-age=31536000Sessions
An encrypted, signed cookie by default; a database driver when you outgrow it. Flash data, remember-me, per-device logout.
session.flash("status", "Saved")?; session.put("cart", &cart)?;Authentication
The user is loaded once per request, from the session or a Bearer token with its abilities, with roles and permissions per tenant.
Routes::new() .get("/orders", index) .require_permission("orders.view")CSRF
Every unsafe method is checked: a hidden field for forms, the X-XSRF-TOKEN header for htmx and JSON.
<form method="post"> {{ csrf_field() }} … </form>Your handler
A plain async fn. Extractors validate the input before it runs; ? turns any error into the right response.
async fn store(State(state): State<AppState>, Valid(form): Valid<NewOrder>) -> Result<Redirect> { let order = form.into_order().insert(&state.db).await?; Redirect::route("orders.show", &[&order.id]) }Views
MiniJinja templates, a UI kit of 70 components, htmx fragments and out-of-band swaps, error pages in your layout.
{% call card("Order #" ~ order.id) %} {{ infolist(order) }} {% endcall %}The response
A full page, an htmx fragment, JSON, a download or a stream, with a request id, and an ETag when you ask for one.
HTTP/1.1 200 OK x-request-id: W5-L3oxyBUY2tvYT content-type: text/html; charset=utf-8
004 Coming from Laravel?
You already know Renox. The compiler just checks your work now.
Routes
Route::get('/orders', [OrderController::class, 'index'])
->name('orders.index')
->middleware('auth');
Route::post('/orders', [OrderController::class, 'store'])
->name('orders.store')
->middleware(['auth', 'throttle:10,1']);Routes::new()
.get("/orders", index).name("orders.index")
.post("/orders", store).name("orders.store")
.throttle(10, Duration::from_secs(60))
.require_auth()Models
class Order extends Model
{
use SoftDeletes;
protected $fillable = ['customer_id', 'total'];
public function customer()
{
return $this->belongsTo(Customer::class);
}
}#[derive(Model, Serialize, Default)]
#[model(soft_deletes)]
pub struct Order {
pub id: i64,
pub customer_id: i64,
pub total: i64,
pub deleted_at: Option<DateTime>,
}
// The customers of a page of orders, in one query:
let customers = belongs_to::<Customer, _, _>(
&db, &orders, |o| o.customer_id,
).await?;Validation
class StoreOrder extends FormRequest
{
public function rules(): array
{
return [
'email' => 'required|email',
'quantity' => 'required|integer|min:1',
];
}
}#[derive(Deserialize, Validate)]
pub struct StoreOrder {
#[validate(required, email)]
pub email: String,
#[validate(required, min = 1)]
pub quantity: i64,
}
async fn store(Valid(form): Valid<StoreOrder>) -> Result<Redirect> { … }Jobs
class SendInvoice implements ShouldQueue
{
public $tries = 5;
public function __construct(public int $orderId) {}
public function handle(): void
{
Mail::to($this->order->email)->send(new Invoice($this->order));
}
}
SendInvoice::dispatch($order->id);#[derive(Serialize, Deserialize)]
pub struct SendInvoice { pub order_id: i64 }
impl Job for SendInvoice {
const NAME: &'static str = "send-invoice";
const MAX_ATTEMPTS: u32 = 5;
async fn handle(self, ctx: JobContext) -> Result {
let order = Order::find_or_404(&ctx.state.db, self.order_id).await?;
ctx.state.mailer.send(invoice(&order)).await
}
}
state.queue.dispatch(SendInvoice { order_id: order.id }).await?;The whole Laravel → Renox guide, from routes to queues, with what is different and why.
005 Benchmarks
All those batteries, a tenth of Laravel's latency.
A real page: 20 rows from SQLite rendered through a template, with every Renox default on (CSP, session, CSRF, auth, locale, error pages). Renox serves 9× Laravel Octane and 16× PHP-FPM, at a tenth of the latency and a tenth of the memory, and keeps about two thirds of bare Axum's throughput.
| Axum (bare) | 15,137 | |
|---|---|---|
| Renox | 9,630 | |
| Laravel Octane | 1,066 | |
| Laravel FPM | 581 |
| Axum (bare) | 4.2 ms | |
|---|---|---|
| Renox | 6.7 ms | |
| Laravel Octane | 59.7 ms | |
| Laravel FPM | 112 ms |
| Axum (bare) | 11 MiB | |
|---|---|---|
| Renox | 12 MiB | |
| Laravel FPM | 106 MiB | |
| Laravel Octane | 128 MiB |
Measured 2026-10-07 on an Intel i7-6700: each server pinned to 2 cores and 1 GB in Docker, oha with 64 connections for 15 s after a 5 s warm-up. The raw numbers and the bare-route results are in benchmarks/RESULTS.md. How it is measured, and how to run it yourself.
006 Deploy
Your whole app is one file. Copy it. Run it.
Views, translations, migrations and public files are embedded at build time. The binary is its own CLI too: migrate, queue:work, schedule:work, db:seed. No PHP-FPM, no node_modules, no runtime to keep patched. Running Renox in production.
007 Built with Renox
Not a hello world. A whole business.
The bike shop runs three stores that sell, rent and service bikes: checkout, rentals, a workshop, service plans, staff roles per store, reports. Every page explains which Renox feature it uses and why.
008 How it compares
The productivity of a full-stack framework, the footprint of a library.
| Feature | Renox | Laravel | Loco | Axum + crates |
|---|---|---|---|---|
| Language | Rust | PHP | Rust | Rust |
| Checked at compile time | yes | no | yes | yes |
| Auth, roles, two-factor, OAuth | yes | with packages | auth only | no |
| Queue and scheduler without Redis | yes | yes | yes | no |
| UI kit and data grid | yes | with Filament | no | no |
| Admin panel, billing, OAuth plugins | yes | with packages | no | no |
| Deploys as one file | yes | no | yes | yes |
| Wiring you write yourself | none | none | some | all of it |
009 From the blog
What's new in Renox.
- Renox 1.0: stable, with a design system and one real exampleRenox 1.0 is on crates.io. The API is stable under semver, the UI kit has a new look and icons, and one complete example explains every page beside its code.
- How a benchmark made Renox 3.3× fasterMeasuring Renox against bare Axum showed every request cloning a 35-field state tens of times. Making it one Arc tripled throughput.
- Meet the bike shop: a whole business built with RenoxThree stores that sell, rent and service bikes, with staff roles per store and reports. Renox's flagship example, live and explained.
● Three lines
Start your next app in Rust without giving up a thing.
$ cargo install renox-cli $ rnx new shop && cd shop $ rnx serve
