View tree, data-r-on:* hooks, and <script type="resuma/state"> — ready before any JS runs.
The lightest path to instant interactivity in Rust
907 bytes to resume. Zero bytes on static pages.
Resuma renders your UI once on the server, serialises signal state into HTML, and lazy-loads only the handlers you touch. No WASM hydration. No component re-execution. Full-stack Flow, server actions, and Resuma OS — one crate.
cargo install resuma · resuma new my-app --template todo · no Node.js for app development
156× smaller initial payload than a default Next.js app — measured on the same counter UX.
Zero-cost static
Marketing pages ship no JavaScript
Docs, blogs, and landing sections without signals or handlers compile to pure HTML. No runtime. No hydration tax. Deploy to the edge and forget about bundle budgets.
Static vs interactive pages →Payload anatomy
Every byte has a job
Hydration frameworks ship the whole app up front. Resuma ships HTML plus a resumability payload — handlers and core load only when needed.
Bootstraps signals from the serialised payload. Enough for static-looking pages to feel alive.
Fine-grained DOM updates, Show/For, effects — fetched on first interaction or prefetch.
onClick and friends live in /_resuma/handler/{Component}.js — pay only for what users touch.
Measured
Counter page — initial load (gzip)
Same UX everywhere: SSR heading + one increment button. Bar width is relative to Next.js (142 KiB). Full methodology →
| Framework | Initial load | First interaction | Static page |
|---|---|---|---|
| Resuma | 907 B | 5.08 KiB | 0 B |
| Leptos | 79.02 KiB | 79.02 KiB | — |
| Next.js | 142.43 KiB | 142.43 KiB | — |
| React (Vite) | 57.99 KiB | 57.99 KiB | — |
| Astro | 57.76 KiB | 57.76 KiB | — |
| SvelteKit | 27.71 KiB | 27.71 KiB | — |
| Qwik | 1.96 KiB | 22.32 KiB | — |
| SolidStart | 16.75 KiB | 16.75 KiB | — |
| templ + HTMX | 16.21 KiB | 16.21 KiB | — |
Hydration frameworks load the same JS on page load — initial and first click match. Resuma static pages ship 0 B client JS. node benchmark/run.mjs
Try it in the docs
Live demos — inside the documentation
Interactive examples run on every docs page: workers, signals, forms, and server functions. The homepage stays lean — open a guide and click.
Resuma OS workers
Run a real #[worker], watch the execution graph, pause and cancel.
→LIVESignals & reactivity
Increment a counter — fine-grained updates, no full re-render.
→LIVEServer functions
Call Rust from the browser without a page reload.
→LIVEForms & #[submit]
Progressive enhancement — works as HTML POST before JS loads.
→LIVEControl flow
Show, For, Match — conditional UI with lazy boundaries.
→LIVELoaders & streaming
#[load] data fetching with cache headers and streaming SSR.
→Positioning
Resumability, not hydration
Three ways to ship interactive UI after the first paint.
Qwik
Resumable JS — tiny preloader, lazy chunks on interaction. Closest mental model to Resuma.
Leptos
Rust SSR + WASM hydration and optional islands.
Resuma
Rust SSR + resumability + lazy JS handlers — no WASM by default.
Performance model
Interactive from the first click
The client never re-runs your component tree. State and handlers are already in the HTML.
Ultralight by design
907 B loader, ~3 KiB core, per-handler chunks — not a monolithic client bundle.
Full Rust stack
#[server] RPC, #[submit] forms, and #[load] data — axum-native, no adapter boilerplate.
Progressive enhancement
<Form submit> works as plain HTML POST before JS loads; runtime enhances in place.
Resumable by default
Every #[component] is a lazy boundary. Handlers externalise to /_resuma/handler/{Component}.js.
Under the hood
How does it work?
One SSR pass. One resumability payload. Lazy execution on the client.
SSR renders once
Rust walks the View tree, emits HTML + data-r-on:* attributes, and serialises signals into <script type="resuma/state">.
Payload travels light
Handler sources move to lazy chunks. computed! / effect! / debounce! replay on the client via rs2js.
Browser resumes
Loader bootstraps signals. Core loads on first interaction. Handlers fetch on demand — or prefetch in viewport.
Components
Write UI once — on the server
view! with JSX-like syntax, fine-grained signals, and onClick handlers that compile to lazy JavaScript.
- signal for reactive state
- computed! / effect! for client replay
- #[component] props builder generated for you
#[component]
fn Counter() {
let count = signal(0);
view! {
<button onClick={count.update(|c| *c += 1)}>
"Count: " {count}
</button>
}
}
// Handler lazy-loads from /_resuma/handler/Counter.jsResuma OS
Durable workers — self-hosted
#[worker] functions, disk-backed queues, cron scheduler, and an ops dashboard. No Redis, no external orchestrator — same binary as your app.
- Execution graphs with SSE event streams
- Pause, resume, cancel from the Flow UI
- Queue recovery and checkpointed state
#[worker(intent = "enrich page")]
async fn enrich(input: Input, ctx: WorkerContext) -> Result<Value> {
ctx.log("fetching");
let page = ctx.tool("fetch", json!({ "url": input.url })).await?;
ctx.progress(50);
let summary = ctx.tool("ai", json!({
"prompt": "Extract key facts",
"data": page
})).await?;
Ok(summary)
}Why Resuma?
Everything you need for modern SSR
Resumable SSR in Rust — one install, progressive enhancement, full-stack Flow when you need it.
Resuma Flow
File-based pages, #[load], #[submit], layouts, middleware — built into the same crate.
Static export
resuma build --static-export scaffolds HTML from src/pages/ for edge-friendly deploys.
Dev experience
resuma dev with HMR WebSocket, resuma new templates (basic, todo, flow, production).
JS bridge
view! translates Rust closures via rs2js. js!{} for escape hatches when you need raw client code.
Islands (optional)
#[island(load = "visible")] for heavy widgets — most UI only needs #[component].
Security built in
Crypto CSRF, security headers, rate limits — see examples/todo for production patterns.
One package
Resuma¹ + Flow²
Two layers, one dependency. Core stays stable; Flow adds routing, data loading, and forms.
RESUMA¹ — CORE
Components & resumability
- view!, #[component], signal
- computed! / effect! / debounce!
- #[server], ResumaApp, ~3KB runtime
FLOW² — FULL-STACK
Pages, loads & submits
- FlowApp, src/pages/, #[layout]
- #[load], #[submit], #[middleware]
- Streaming SSR, cache headers
AI assistants
Build faster with Cursor, Codex, or Gemini
Install the Resuma agent skill in one command — reactive view! rules, Flow patterns, server actions, and debugging checklists built in.
Integrations
Database, auth, and tooling
Integration guides for SQLx, Turso, auth, validation, i18n, and E2E testing.