Skip to content

Inertia RustReact pages. A Rust server. No API.

An Inertia.js starter kit for Rust: React 19 and shadcn/ui pages, served by a Loco server with auth, accounts, live updates and generators built in. One binary, SQLite, and nothing to keep in sync between them.

Inertia Rust

A controller and the page it renders โ€‹

The controller loads the data and hands it to a React page as props. There's no JSON API in between, and nothing to keep in sync.

rs
// src/controllers/projects.rs
async fn index(
    current: CurrentAccount,
    State(ctx): State<AppContext>,
    inertia: Inertia,
) -> Result<Response> {
    let projects: Vec<Value> = projects::Model::list(&ctx.db, current.account.id)
        .await?
        .iter()
        .map(projects::Model::to_props)
        .collect();
    render(inertia, "projects/index", json!({ "projects": projects })).await
}
tsx
// frontend/pages/projects/index.tsx
import { Link } from "@inertiajs/react"

import { useCurrentAccount } from "@/hooks/use-current-account"
import { projects as routes } from "@/routes"

interface Project {
  id: number
  name: string
}

export default function Projects({ projects }: { projects: Project[] }) {
  const { slug: accountSlug } = useCurrentAccount()

  return (
    <ul>
      {projects.map((project) => (
        <li key={project.id}>
          <Link href={routes.show({ accountSlug, id: project.id })}>
            {project.name}
          </Link>
        </li>
      ))}
    </ul>
  )
}

cargo loco generate scaffold projects name:string! writes both, plus the model, migration, routes and tests.

The Inertia way โ€‹

No API layer

Controllers render pages, not JSON. Inertia sends the page's props on navigation and React renders them.

Props from Rust to React

A controller passes props to render(inertia, "projects/index", โ€ฆ). Routes are typed on both sides, generated from one route table.

Mutations redirect

Forms post, the controller validates and redirects with a flash or an error bag. Errors show up on the right fields, no client-side state to manage.

Coming from Rails? The kit follows the Inertia Rails React Starter Kit, and Rails โ†’ Loco maps each rails command to its equivalent here.

The kit's home page, light themeThe kit's home page, dark theme

The numbers โ€‹

Both kits as production Docker images on the same workstation, 4 pinned CPUs each, SQLite, SSR off, Rails with YJIT and Puma 4ร—3. Medians of 5 runs, 2026-10-04.

57 ms
boot to first response, vs 1.6 s for the Rails kit
5โ€“8ร— less
memory: 42 / 65 MiB idle / after load, vs 210 / 509 MiB
4.5โ€“11ร—
requests per second, e.g. 26,435 vs 5,928 on the signed-in page (Inertia visit)
2.1 ms
p99 on the signed-in page, vs 11.2 ms (5.4ร— lower)
52 MB
compressed Docker image, vs 207 MB

The caveats are real. Under a 4 GB container limit, 0.17% of SQLite writes from 32 writers failed with a 500 (pool timeouts during write stalls; none with 32 GB), where Rails had none. With SSR on, Node is the bottleneck and throughput is about equal. The Rails kit builds its image faster from cold and reloads code instantly. Method, ranges and every caveat: the full benchmark.

Get started โ€‹

Click Use this template on GitHub, or clone it. You need Rust (rustup) and Node 22.

sh
git clone https://github.com/cole-robertson/inertia-rust-starter-kit.git myapp
cd myapp
bin/rename my_app "My App"   # optional, but do it before the first bin/setup (see below)
bin/setup                    # npm ci, cargo build, migrate, seed, then bin/dev

Open http://localhost:5150 and sign in as one@example.com / Secret1*3*5*. Then build your app: rename it, scaffold a resource, add jobs and mail, deploy.

FAQ โ€‹

Why Rust? โ€‹

For one small binary that boots in milliseconds, uses a fraction of the memory and serves more requests per core, with the compiler checking the server code and typed routes shared with React. Loco brings Rails' shape to Rust: generators, migrations, jobs, mailers, tasks. The trade is slower builds and no autoloading; see the benchmark for both sides.

Where does it come from? โ€‹

It started as a port of the Inertia Rails React Starter Kit, and it still matches its routes, pages and messages, checked by a test that compares both kits' responses. Organizations are added on top. Every intended difference is listed in Parity with the Rails kit.

Can I use Postgres? โ€‹

Not out of the box. The kit ships SQLite (WAL mode) for the app and its job queue, and the benchmark, the deploy targets and some code (src/db.rs) assume it. Loco and SeaORM support Postgres, so a switch is possible, but you'd be doing it yourself.

Do I need to know Rust? โ€‹

You'll read and write some. The generators write most of the server code, the pages are plain React and TypeScript, and AGENTS.md plus the kit's skills give a coding agent the exact steps for each task. Rails experience carries over: Rails โ†’ Loco.

Is it production-ready? โ€‹

It's v0.1. It has tests (Rust request and protocol tests, Playwright in client- and server-rendered modes), a security review and CI on every change, and the live demo runs it. But it's new, it has few users yet, and SQLite means one app server per database. Read the changelog and judge for yourself.

Why accounts by default? โ€‹

Most business software keeps data per organization, and accounts are cheap to keep but expensive to add to an app that already has data. If your app has no teams, the accounts guide shows how to flatten it.

Released under the MIT License.