π Resuma
The first Rust web framework with SSR + Resumability + Islands + Server Actions + a friendly JS Bridge.
Zero hydration, true resumability, lazy handler chunks, automatic RustβJS handler compilation.
Install: cargo install resuma Β· Docs: resuma-docs.fly.dev Β· API: docs.rs/resuma Β· Repo: GitHub
What is this?
Resuma is a from-scratch Rust framework for building modern web apps with resumability instead of hydration:
Resumability vs hydration
| Aspect | Classic SSR + hydration | Resuma |
|---|---|---|
| Client work after load | Re-run components to attach listeners | Resume serialized state and handlers |
| Initial JS | Grows with app size | ~3KB runtime + lazy chunks |
| Interactive boundaries | Often manual | Every #[component] is resumable; #[island] optional |
| Server RPC | Custom wiring | #[server] async fn + built-in endpoint |
| Handler code on client | Ship framework runtime + app logic | Compile handlers to small JS via rs2js |
| Templates | Varies | JSX-like view!{} β no extra sigils |
The mental model: components only run on the server. The browser never re-executes them. SSR serialises signals and handler references into HTML; the tiny client runtime resumes execution lazily β on first interaction or when a boundary scrolls into view.
Hello, Resuma
use *;
async
That single click handler is automatically translated to JavaScript by resuma-macros (rs2js), lazy-loaded on first interaction, and runs against the resumed signal state. No hydration, no re-execution, no WASM bundle.
Server actions
async
#[server] registers an RPC endpoint at /_resuma/action/search. The handler is dispatched there transparently.
Islands (optional)
Every #[component] is already resumable (lazy handler chunks + viewport prefetch). Use #[island] only for heavy client bundles, load = "visible", or dev HMR.
Resuma Flow (full-stack layer)
One crate β resuma includes core + Flow in a single dependency.
| Resuma Flow | Purpose |
|---|---|
FlowApp |
App builder with page registry |
#[load] |
Server data before render |
#[submit] |
Form mutations |
src/pages/ |
File-based pages |
See docs/PACKAGE.md and docs/FLOW.md.
Live docs site: https://resuma-docs.fly.dev Β· or cargo run -p example-website β http://127.0.0.1:3000
Architecture
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β resuma crate (v0.3) β
β β
β core βββΊ ssr βββΊ server (axum) β
β β GET /_resuma/runtime.js β
β β POST /_resuma/action/:name β
β ββββΊ flow + router (pages, loads, submits) β
β β
β resuma-macros (separate crate) β
β view! / #[component] / rs2js β JS handlers β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HTTP
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser (~3KB) β
β parse resuma/state Β· delegate events Β· lazy handlers β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
See docs/ARCHITECTURE.md for a deep dive.
Security: docs/SECURITY.md β CSRF, headers, rate limits, production checklist.
Backend patterns: docs/BACKEND.md β live in examples/todo.
All docs: docs/README.md Β· cargo run -p example-website
Publishing: docs/PUBLISHING.md β crates.io release checklist
Project layout
Resuma/
βββ crates/
β βββ resuma/ # single runtime crate (core, ssr, server, flow, cli)
β βββ resuma-macros/ # proc-macros + rs2js (required separate crate)
βββ runtime/ # TypeScript source for the ~3KB client runtime
βββ examples/
βββ counter/
βββ todo/
βββ flow-demo/
βββ flow-pages/
βββ website/ # docs site
Docs: docs/README.md Β· live site: cargo run -p example-website
Getting started
Pre-requisites: Rust 1.91+ (rustup).
Install from crates.io (recommended)
- Crate: crates.io/crates/resuma
- API docs: docs.rs/resuma/0.3.0
- Proc-macros: docs.rs/resuma-macros/0.3.0
- Guide: resuma-docs.fly.dev/docs
Library only (no CLI binary):
[]
= { = "0.3", = false }
= { = "1", = ["full"] }
From source (development)
# Examples
What works in v0.3
β
Signal<T>, use_signal, use_effect, use_computed (SSR-only; use macros for client replay)
β
view!{} macro with JSX-like syntax (no $ noise)
β
#[component] with auto-generated props builder β resumable boundary by default
β
#[server] async actions with JSON-RPC endpoint
β
#[island] optional β heavy widgets, visible load, dev HMR
β
js!{} escape hatch for raw JS handlers
β
Rust β JS compiler for common handler patterns
β
SSR with resumability payload embedded in HTML
β
Lazy handler chunks externalized from payload + viewport prefetch
β
~3KB client runtime (lazy event delegation + signals + RPC)
β
axum-based server with built-in /_resuma/* routes
β
File-based routing scanner (src/pages/[id].rs β /users/:id)
β
Flow static routes receive FlowRequest (query, headers, method)
β
computed! / debounce! / effect! β client-replayable (rs2js)
β
#[island(load = "visible")] lazy island loading
β
Island HMR refresh + dev WebSocket (resuma dev)
β
resuma build --static export scaffold
β
resuma CLI: new (basic/todo/flow), dev, build, routes
Resumability model (default)
Every #[component] is a resumable boundary:
- SSR always β Rust renders HTML on the server
- Handlers register under the component chunk (lazy-fetched from
/_resuma/handler/{Component}.js) - Small page handlers stay inline in the payload (
__page__, under 256 bytes) - Signals +
computed!/effect!β client replay without re-running components
#[island] is optional β use it only for heavy lazy JS bundles, load = "visible", or dev HMR. Most apps need only #[component] + view!.
Client-side reactivity
use_signal updates work on the client via the resumability payload. For derived state and effects in the browser, use computed!([deps], move || β¦), effect!([deps], move || β¦), and debounce!([deps], ms, move || β¦) (rs2js-translated). Plain use_computed() / use_effect() run on SSR only.
Roadmap (v0.4+)
- Partial pre-rendering (PPR) β server shell + dynamic boundaries
- Devtools extension for resumability payload inspection
- First-class TypeScript bindings for
js!{}blocks - WASM-backed islands for compute-heavy code (opt-in)
Already shipped in v0.3: resumability everywhere, client effect replay, lazy handler externalization, viewport prefetch, dev HMR, static export, HTTP context in Flow routes, env-based bind, flow scaffold, crypto CSRF. v0.2 brought single-crate layout, streaming SSR (Flow), layouts, file-based routing, security defaults, crates.io publish.
Why "Resuma"?
Spanish for both resumes (continues) and summary β fitting because the framework's superpower is resuming execution from a serialised summary of the server-side render.
License
MIT OR Apache-2.0