Use it all together, or pick only what you need.
v1.10.0 · September 2026

A Rust framework for
compiled web applications

Build compiled websites, APIs, and admin surfaces in one fast, secure, compact Rust runtime — or adopt only the pieces you need.

Lithair can serve the compiled frontend itself, keep active state in memory for fast reads, and bring security features close to the runtime — while keeping auth, policy, event history, and other capabilities optional. Use it all together, or pick only what you need. When the workload fits, that can mean fewer services, fewer network hops, and a smaller operational footprint.

Serve the compiled site from the same runtime — this website does
Add auth, policy, and event history only when you need them
Fast in-memory reads when the active state fits
Use Lithair on its own or alongside SQL
main.rs
// A compact backend for workloads that fit the model.
use lithair_core::app::LithairServer;
use lithair_core::DeclarativeModel;
use serde::{Deserialize, Serialize};

#[derive(DeclarativeModel, Serialize, Deserialize, Clone, Debug)]
struct Article {
    #[http(expose, validate = "non_empty")]
    #[lifecycle(versioned = 3)]
    title: String,
    #[http(expose)]
    content: String,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    LithairServer::new()
        .with_port(3000)
        .with_model::<Article>("./data/articles", "/api/articles")
        .serve()
        .await?;
    Ok(())
}

Declare a model, get a CRUD API — backed by an in-memory store and event log.

Recent additions · September 2026

Twenty-two releases shipped between v0.6.0 and v1.10.0. What landed:

v0.6.0

Vhost routing

A single binary serves multiple hostnames, each with its own frontend. Blog →

v0.7.0

Programmatic sessions

Sessions API plus per-model gating via with_models_require_session(true).

v0.8.0

Auto-compaction & metrics

.raftlog auto-compaction, per-model storage stats, Prometheus on /metrics.

v0.9.0

Programmatic handlers

with_model_ref returns a handler that shares CRUD with the gated REST API.

v0.10.0

SSE broadcaster

SSE broadcaster auto-wired to handlers at serve-time — no manual plumbing.

v0.11.0

Incremental SSE streaming

SSE-over-HTTP streams incrementally; RouteResponse migrated to BoxBody.

v0.12.0

Memory/disk retention tiering

#[retention(memory = N)] caps RAM residency; #[pinned] fields survive eviction and stay queryable. Count, duration, or byte-budget — composable, with runtime env overrides. Memory-first, not memory-only.

v0.13.0

Built to be operated

Graceful shutdown (serve_with_graceful_shutdown — the socket closes before a 5s drain, so in-flight requests aren't cut), full observability (tracing spans on the critical paths, an X-Request-ID on every response, and an opt-in OpenTelemetry OTLP exporter), and operations runbooks for Docker, systemd, and Kubernetes. The cluster is now documented as stable within a measured envelope. Blog →

v0.14.0

Update content & frontend without a restart

Frontend lifecycle admin API (/_admin/frontend/*) hot-reloads a vhost's assets in memory under a write lock — redeploy becomes one API call, not a restart. Logical backup/restore (/_admin/data/* export) plus a lithair verify CLI that checks a restored event store's hash chain offline.

v0.15.0

Secure by default, safe to extend

Admin planes secure by default — with_data_admin() auto-applies RequireAuth over /_admin/*, session-aware (#143). Plus lithair_core::prelude, logical backup import, and two v1.0 gates: unknown macro keys are now a compile error (G2), API surface classified + MSRV locked (G3).

v0.16.0

Role-scoped admin access

Tier admin access by role instead of all-or-nothing: with_admin_roles(frontend_roles, data_roles) restricts the frontend plane and the data plane independently — a content-manager who can publish and reload frontends without the keys to the whole server, vs admin vs super-admin. RouteGuard::RequireRole is now implemented (fails closed on a wrong role). The embedded /_data dashboard gains a Frontends tab (list, version, reload) — server-enforced. Opt-in and backward compatible.

v1.0.0

The stable release

What 1.0 promises is now a contract, not an aspiration: an api-stability.md tiering (stable / unstable / hidden) with a locked MSRV. All eight v1.0 roadmap gates are closed. Stale deprecations and ~840 lines of dead surface were removed; no on-disk format change since 0.13. The contract is stable from here.

v1.1.0 – v1.3.0

Post-1.0 hardening, cleanup & test coverage

Three maintenance releases on top of the stable contract — no on-disk format change, and the stable API surface is unchanged (the one addition aside). v1.1.0 hardens the write path: a valid-JSON non-object body (42, "abc", [..]) no longer panics the cluster request task (now a 400), and error responses build through serde_json::json! instead of raw format!, closing a JSON-injection path in error bodies. v1.2.0 adds one honest extension point — with_tracing_layer(...) for a custom log provider (rolling file, Loki, syslog, OTLP) — and fixes LT_LOG_LEVEL, which was advertised but never applied. v1.3.0 is a test-workflow release: compile-fail tests now lock the declarative-macro surface (a typo'd attribute key or a known key in the wrong position fails the build), a documented test pyramid runs per-PR in CI, and resurrecting the dormant suites caught six real bugs — including a data-loss one. The only removal is a broken, undocumented single-file log-rotation knob (LT_MAX_LOG_FILE_SIZE) that could delete event history. No API change. Across the three, roughly 2,000 lines of dead surface were removed and the legacy “Raftstone” name was fully retired.

v1.4.0 – v1.10.0 · latest

The consumer-driven releases

Seven releases in under a month, and nearly every line came from the first production consumer — a blog engine built on Lithair. The framework did not grow by roadmap; it grew where a real site hit a wall. Blog →

v1.4.0 is the configuration-honesty release: an invalid config.toml now surfaces instead of silently booting on defaults, a meta-test keeps the config docs matching what the code reads, and extensionless clean URLs (/posts/hello) stop downloading as application/octet-streamupdate_asset_with_mime lets a caller declare the type. v1.5.0 makes #[server(main)] — the front door — actually compile for a crates.io consumer, locked on three layers of tests; graceful shutdown now really drains (with_shutdown_grace), opt-in strict_host_routing() answers 421 on an unknown host, and the first Criterion benchmark confirms O(1) vhost lookup. v1.6.0 serves a site's own /404.html on a miss, vhost-aware. v1.7.0 is self-publishing: pushing a v* tag ships the GitHub Release and crates.io with no manual step.

v1.8.0 adds on_mutation — a native Rust hook on every model write, fed by the same channel as the SSE stream, run on its own isolated task — and with_auth_path, which moves the login off its guessable /auth default. It also fixes panic isolation in release builds: panic = "abort" had been turning every caught panic into a process crash in production, and a meta-test now forbids it. v1.9.0 is the browser-session release: the login sets a session_token cookie (Secure; HttpOnly; SameSite=Lax), the gate and guards accept it, logout clears it — and CookieConfig becomes the single cookie authority, so the session options that were read but never applied now apply. RBAC session cleanup finally runs; an expired session is no longer reported valid. v1.10.0 rejects cross-site requests on cookie-authenticated mutations with 403 (Sec-Fetch-Site first, then Origin/Referer against Host; Bearer clients and native tools without browser headers are unaffected), and makes frontend asset deletion effective and persistent across restarts.

Named honestly: v1.9.0 unifies the default cookie name to session_token (the middleware default was session_id, a split-brain waiting to happen), SessionMiddleware now prefers Bearer over cookie, and with_rbac_config must be called inside a tokio runtime. v1.10.0 enables the cross-site check by default — LT_SESSION_CROSS_SITE_CHECK=Off is the documented opt-out. No on-disk format change across the seven.

What is Lithair?

Lithair is a Rust web framework for building compiled websites, APIs, and admin surfaces in a compact runtime. It explores a simpler backend shape: keep the system all in one when that helps, or pick only the features you need — from frontend serving and in-memory state to auth, policy, admin tooling, and event history.

Conventional backend stack

Browser React/Vue/Svelte build
↓ HTTP
Edge Reverse proxy, TLS, static files
↓ HTTP
App Express/Django/Spring + ORM
↓ TCP + SQL
Data PostgreSQL/MySQL + Redis
Ops Docker, K8s, monitoring...

More layers, more flexibility, and a broader operational surface.

Lithair on a fitting workload

Browser Your frontend (any framework)
↓ HTTP

Single Binary

HTTP Router + static files (from RAM)
API Auto-generated from your models
Data In-memory (SCC2) + event log
Auth Sessions, RBAC, MFA — built-in

A smaller default runtime surface, with direct in-process access to active state.

Lithair is not a universal replacement for SQL or traditional stacks. Hybrid architectures are normal: keep SQL where it adds leverage, and use Lithair where a memory-first model removes unnecessary layers.

Why Lithair?

Because many teams know how quickly a backend grows in moving parts. Lithair comes from a practical question: when the workload fits, can we keep the system smaller without losing the capabilities that matter?


  REQUEST                     ACTIVE STATE (In Memory)          DURABILITY
  ───────                     ────────────────────────          ──────────

  GET /api/articles    ───>    ┌────────────────────┐
                                │                    │
       memory read              │  articles: {       │
       current state            │    "abc": {...},   │
       no SQL round trip        │    "def": {...},   │
                                │  }                  │
  POST /api/articles   ───>    │                    │   ───>   events.raftlog
                                │  sessions: {...}   │          (append-only)
       update active state      │  users: {...}      │
       + persist event           │  static_files: {...}│
       for replay               │                    │
                                └────────────────────┘
  STARTUP                              <───           snapshot + replay
                                load snapshot,               events since
                                replay events                last snapshot
                                into SCC2

Fast access to active state

Lithair keeps the hot state in memory, which can remove a database round trip from read-heavy paths and simplify request handling when the workload fits the model.

Built-in event history

Changes are recorded as immutable events. That gives you auditability, replay, and a clear record of how state evolved over time.

Smaller default operating surface

State snapshots plus event replay keep persistence close to the runtime. The result is a more compact default deployment, with fewer moving parts to configure and operate.

"The goal is not to argue against proven stacks. The goal is to ask whether some products can ship with fewer layers and still be easier to build, run, and understand."

When Lithair is a good fit

Lithair tends to work best when the workload is bounded, the active state benefits from living in memory, and event history adds real value.

1

Bounded working set

Your active application state fits comfortably in memory and can be rebuilt from snapshots plus events.

Good signal
state size stays predictable
and operationally manageable
2

Read-heavy or latency-sensitive paths

You want direct in-process access to active state instead of a database round trip on the hot path.

Good signal
most requests read current state
from a bounded dataset
3

Auditability and replay

You want a durable event history for compliance, debugging, operational traceability, or state reconstruction.

Good signal
how state changed matters
as much as the current state
4

Progressive adoption

You want to introduce Lithair in one bounded service or feature, while keeping SQL or other components where they already work well.

Good signal
hybrid architecture is acceptable
and rollout can be incremental
A good fit is about workload shape, not ideology.

Architecture

Lithair keeps the default runtime compact, but the pieces are modular. Use the parts that help and integrate with the rest of your stack where needed.

Model-driven API

Define your model once and generate routine API and validation layers from it, reducing repetitive backend plumbing on suitable workloads.

State evolution

Evolve models over time while keeping state reconstruction and event history explicit instead of spreading that logic across multiple layers.

Auth and policy

Sessions, roles, and permissions can live close to the runtime instead of being spread across separate services from day one.

Security capabilities

Optional auth features such as MFA can be added when the product needs them, without forcing them into every deployment.

HTTP layer

Serve routes, APIs, and static assets from the same runtime when that keeps the system smaller and easier to operate. Here, Astro builds the site into static assets, then Lithair loads and serves them from memory at startup.

Operational safeguards

Basic protections such as rate limits, IP rules, and CORS handling are available in the runtime by default.

Event history

Keep a durable record of change and optional historical views when the domain needs replay, debugging, or auditability.

Admin surface

Built-in admin tooling can reduce the amount of backoffice code you need to write early on.

Optional replication

When distribution is needed, replication can be added as part of the architecture instead of becoming day-one complexity.

When a traditional stack is still a better choice

Lithair is not the best answer for every backend. Conventional stacks remain the better choice when their strengths match the problem.

Traditional stacks usually win when

  • Your domain depends on rich relational queries, joins, or reporting.
  • Your data footprint is too large or too variable for a practical memory-first model.
  • You rely on mature SQL tooling, analytics workflows, or established database operations.
  • Your team already has strong leverage around Postgres and a conventional backend stack.

Hybrid adoption remains a strong option

  • Keep SQL for analytical, relational, or reporting-heavy workloads.
  • Use Lithair for one bounded service or feature where active state benefits from living in memory.
  • Adopt progressively instead of forcing an all-or-nothing rewrite.
  • Choose architecture by workload, not by ideology.

Performance

Lithair can be very fast on the right workload because active state is kept in memory and reads can avoid a database round trip on the hot path.

Fast reads

When requests hit active in-memory state, Lithair can deliver very low-latency reads on suitable workloads.

Workload-dependent results

Latency and throughput depend on data shape, read/write mix, snapshot strategy, concurrency, hardware, and deployment shape.

Reproducible claims only

Any benchmark should be shared with its dataset, hardware, workload profile, and test method. Numbers without context are not useful.

Any numbers shown for Lithair should be treated as illustrative, reproducible, and workload-specific — not as universal promises. The practical claim is narrower: when the model fits, Lithair can remove layers that often add latency, operational overhead, and implementation complexity.

Get started

Try the model in a few minutes.

# Install the CLI

$ cargo install lithair-cli

# Create a new project

$ lithair new my-app

# Run it

$ cd my-app && cargo run

# Your server is running

✓ Listening on http://127.0.0.1:3007

✓ Active state loaded in memory

✓ Event log ready

YR

Yoan Roblet

DevOps Engineer (5 years) · Ops (20 years) · Developer

I love DevOps. For large teams and large systems, the surrounding tooling is often the right choice. But after enough time operating complex systems, it is natural to ask whether every project really needs the full surface area.

Lithair started as a practical experiment: when the workload fits, can we ship something useful with fewer layers, less glue, and a shorter path from code to production? The goal is not to dismiss the rest of the ecosystem. It is to see where a smaller model is enough — and sometimes genuinely simpler to build and run.