The Inertia.js server-side protocol superset, for Rust.
Build modern single-page apps in React, Vue, or Svelte β without writing a JSON API, a client-side router, or a single fetch. Your Rust handlers return typed props, and the frontend hydrates as if the page was server-rendered. Because it was.
- β¨ What is Inertia, and why a Rust adapter
- π¦ Installation
- π Quick Start
- π§ A short tour
- π Documentation
- ποΈ Feature Flags
- π§ͺ Example App
- πΊοΈ Status & Roadmap
- π Acknowledgements
- π§ͺ Testing
- π Changelog
- π€ Contributing
- π Security Vulnerabilities
- π Support This Project
- β Star History
- π License
Inertia.js is a glue layer that lets a classic server-rendered backend drive a modern SPA frontend. The server returns a page object (component name + props); the official Inertia client adapter for React/Vue/Svelte takes care of mounting the component, hydrating props, intercepting links, and making subsequent navigations into JSON XHRs.
veer is a clean-room Rust implementation of the server side of the Inertia v3 protocol. It targets axum out of the box; the protocol core is framework-agnostic, so adapters for other Rust web frameworks slot in beside it.
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ
β Rust handler β ββ page object βββΆ β Inertia client (JS) β
β inertia.render(...) β (JSON) β React / Vue / Svelte β
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββ
β² β
ββββββββββββββ navigation XHR ββββββββββββββββββββ
Highlights
- π¦ The full Inertia v3 protocol (client 3.8), checked against the Laravel adapter and the real client
- β‘ First-class axum adapter: one extractor, one tower layer
- π¦ Every prop type: partial reloads, deferred, optional, once, merge, infinite scroll, big integers
- β Forms the Inertia way: validation errors, flash data, error bags, Precognition live validation, file uploads
- π₯οΈ SSR through the official Node/Bun renderer, with fallback to client rendering
- βοΈ Vite dev server + production manifest integration, and embedded assets for a single-binary deploy
- πͺ’ End-to-end TypeScript: page props and route helpers generated from your Rust types
- π CSRF protection, history encryption, and a recorder for the Inertia DevTools extension
- π§© Framework-agnostic protocol core with pluggable sessions, root views and SSR clients
[dependencies]
veer = "0.3"Or with cargo add:
cargo add veerThe default feature set includes the axum adapter. See Feature flags for everything else. Coming from an older version? Read the upgrade guide.
use axum::{routing::get, Router};
use veer::{Inertia, InertiaConfig, InertiaLayer, MinimalRootView};
#[tokio::main]
async fn main() {
let cfg = InertiaConfig::new()
.root_view(
MinimalRootView::new()
.title("Acme")
.vite_entry("/src/main.tsx"),
);
let app = Router::new()
.route("/", get(|inertia: Inertia| async move {
inertia.render("Home", serde_json::json!({ "msg": "hello" }))
}))
.layer(InertiaLayer::new(cfg));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}The Inertia extractor reads the request. render(component, props) returns a builder. The layer handles the rest of the protocol β initial HTML on first load, JSON on XHR navigations, 409 for asset-version mismatches, 303 for redirects, partial reloads. Continue with the getting started guide.
Load data only when the page needs it. Closures run only when the response needs their value, and they return plain Rust types. β Props
inertia
.render("Users/Index", UsersIndexProps { users })
.lazy("stats", || async { load_stats().await }) // on request only
.deferred("activity", "default", || async { load_activity().await }) // after first render
.once("plans", || async { load_plans().await }) // one time per client
.prop("feed", Prop::scroll(move || async move { load_feed(page).await })) // infinite scrollHandle a form like a classic server app. Validate, redirect, and the errors and the flash message show on the next page. β Forms and validation
async fn users_store(inertia: Inertia, Validated(body): Validated<NewUser>) -> impl IntoResponse {
// Invalid input went back to the form with its errors already.
create_user(body).await;
inertia.redirect("/users").with_flash("success", "User created")
}Share data with every page. β Shared props
let cfg = InertiaConfig::new().share(|req| {
let user = req.extension::<CurrentUser>().cloned(); // set by your auth middleware
async move { json!({ "auth": { "user": user } }) }
});Get TypeScript types from your Rust structs. β TypeScript bindings
#[derive(Serialize, TS)]
#[ts(export)]
pub struct UsersIndexProps { pub users: Vec<User> }
veer::register_page!(UsersIndexProps, "Users/Index");
// The component name comes from the registration.
inertia.page(UsersIndexProps { users })import { users, type UsersIndexProps } from "./gen";
<Link href={users.show.url({ id: user.id })}>{user.name}</Link>| Guide | What it covers |
|---|---|
| Getting started | Install, first page, how a request flows, the frontend entry point |
| Props | Partial reloads, lazy / deferred / once props, merging, infinite scroll, shared props, big integers |
| Forms and validation | Validated, InertiaForm, validation errors, error bags, flash data, Precognition, file uploads |
| Redirects and history | redirect, back, external redirects, URL fragments, history encryption |
| Sessions | The cookie store, tower-sessions, writing your own store |
| Error pages | 404 and application errors as Inertia pages |
| Testing | veer::testing: page assertions for your handlers |
| Vite, SSR and assets | ViteRootView, server-side rendering, embedded assets, <head> elements |
| TypeScript bindings | Typed page props and route helpers generated from Rust |
| CSRF protection | CsrfLayer and the XSRF-TOKEN convention |
| DevTools | The recorder for the Inertia DevTools browser extension |
| Architecture | Crate layout, protocol coverage, extension points |
| Upgrading | Every breaking change of each version and what to do |
API reference: docs.rs/veer. For the client side, use the Inertia documentation.
| Flag | Default | Effect |
|---|---|---|
axum |
on | Axum extractor + tower layer + InertiaForm body extractor |
multipart |
off | File upload support (UploadedFile, MultipartStream) |
ssr |
off | HTTP SSR client (reqwest) |
cookie-session |
off | Signed-cookie session store |
tower-sessions |
off | Session store backed by tower-sessions |
validator |
off | Validated<T> extractor + IntoErrorBag impl for validator::ValidationErrors |
garde |
off | GardeValidated<T> extractor + IntoErrorBag impl for garde::Report |
csrf |
off | CSRF protection (CsrfLayer) |
embed |
off | Embedded-asset serving for single-binary deploys (EmbeddedAssets) |
devtools |
off | Recorder + read API for the Inertia DevTools browser extension |
ts |
off | End-to-end TypeScript bindings codegen (ts-rs + inventory) |
testing |
off | Test helpers (veer::testing) |
Disabling a feature drops its transitive deps entirely.
A complete end-to-end demo lives at examples/axum-react-todo/ β axum backend + React/Vite frontend, in CSR and SSR mode. It has a todo list with validation, flash messages and Precognition, and a showcase page for once, deferred, rescued, scroll and big-integer props with generated TypeScript types.
cd examples/axum-react-todo
just # CSR mode β open http://localhost:5173
SSR=1 just dev # SSR mode β open http://localhost:3000veer is pre-1.0. The protocol surface follows Inertia v3 as of client 3.8 / inertia-laravel 3.5; the coverage table has the detail. Planned:
- Adapters for
actix-webandrocket - Typed route-param inference (today:
string | number; goal: read each handler'sPathextractor and emit the matching TS type)
Contributions, bug reports, and protocol-conformance fixtures welcome.
The protocol is Inertia.js by Jonathan Reinink and contributors. veer is an independent server-side implementation for Rust, modeled on the Laravel adapter's behavior.
cargo test --all-featuresPlease see CHANGELOG for more information on what has changed recently.
Issues and pull requests are welcome. You can also join our Discord server to discuss ideas and get help: Discord Invite.
Please report security vulnerabilities to security@climactic.co.
Veer is free and open source, built and maintained with care. If this crate has saved you development time or helped power your application, please consider supporting its continued development.
Your logo here β Become a sponsor and get your logo featured in this README and on our website.
Interested in title sponsorship? Contact us at sponsors@climactic.co for premium placement and recognition.
Dual-licensed under MIT or Apache 2.0 at your option. Please see MIT and APACHE for more information.