Axeon 1.2 is here

The Rust web framework that feels like Express.

Write handlers as simply as in Express and get Rust's speed, memory efficiency and safety. Built on hyper, batteries included, and ready for production.

$ cargo add axeon
src/main.rs
use axeon::Server;

fn main() {
    let mut app = Server::new();
    app.get("/", |_req| async { "Hello, World!" });
    app.listen("127.0.0.1:3000")
        .expect("server failed to start");
}
Terminal
$ cargo run
$ curl -i http://127.0.0.1:3000/
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8

Hello, World!
176kJSON requests per second
8.9 MiBmemory under load
4–5×the throughput of Express
2 msp99 latency

Apple M1, 128 keep-alive connections, best of three runs. Methodology and caveats.

Everything a backend needs

Small surface, no surprises. The pieces you reach for in every project are already there and already secure.

Simple by design

Express-like routing and middleware. Handlers return plain values: text, Json(..), (201, body), Option or Result.

Fast and lean

Within ~10% of the fastest Rust frameworks, at about 4–5× Express throughput on 1/100th of the memory. Routing time doesn't grow with route count.

Batteries included

Validation, JWT and API keys, sessions, CSRF, rate limits, idempotency, caching, templates, uploads, server-sent events and WebSockets.

Secure by default

Size limits, timeouts, slow-client protection, security headers, rate limiting, CORS, panic isolation and constant-time secret comparison.

Production ready

HTTP/1.1, HTTP/2 and HTTPS, graceful shutdown with a drain period, health checks, Prometheus metrics and request IDs.

Plays well with others

Use any tower layer (all of tower-http) as middleware, or run an Axeon app as a tower Service. No database lock-in.

Reads like the code you meant to write

Typed helpers parse input and answer bad input with the right status code. Middleware wraps what you choose. Everything is plain Rust, with no macros to learn.

  • Static paths beat parameters, and conflicts are caught at startup
  • Errors become JSON responses, and panics never leak internals
  • Test the whole pipeline in-process, with no ports
Routes
app.get("/users/:id", |req| async move {
    let id: u64 = req.param("id")?;          // 400 if not a number
    Ok::<_, ServerError>(Json(json!({ "id": id })))
});

app.post("/users", |req| async move {
    let user: NewUser = req.json()?;         // 415 / 400 / 422 for bad input
    Ok::<_, ServerError>((201, Json(user)))
});
See the full recipe

The Cookbook

44 complete, copy-pasteable recipes. Every program is compiled and tested against Axeon in CI, so what you copy works.

Getting started

Hello, World

A server in a handful of lines. Create a project, add Axeon, and answer your first request.

Open recipe
Getting started

Routing

Path parameters, wildcards, route groups, and how conflicts are settled.

Open recipe
Requests and responses

A JSON API

Parse JSON bodies, query strings and typed path parameters, and get the right 4xx status for free.

Open recipe
Getting started

A complete REST API

CRUD for one resource with shared state, validation, proper status codes and tests, in one file.

Open recipe
Requests and responses

Validation

Check incoming data and answer 422 with a per-field list of problems.

Open recipe
Requests and responses

Error handling

Return typed errors with ?, shape every error response yourself, and keep internals out of the response.

Open recipe
Requests and responses

Building responses

Status codes, headers, redirects, downloads and streaming, when a plain return value is not enough.

Open recipe
Requests and responses

HTTP caching and ETags

Answer 304 Not Modified, set Cache-Control, and skip the expensive work when the client already has the data.

Open recipe
Requests and responses

Language negotiation

Pick the best supported language per request from Accept-Language, a query parameter or a cookie.

Open recipe
Middleware and state

Middleware

Closure middleware, middleware as a type, scoping to a router or one route, and passing data to handlers.

Open recipe
Middleware and state

Shared state

Register database pools, clients and counters once and read them from any handler.

Open recipe
Middleware and state

Hardening an API

Security headers, CORS, rate limiting, compression and request limits in one setup.

Open recipe
Auth and sessions

JWT authentication

Issue tokens at login and protect a router so handlers only run for valid bearer tokens.

Open recipe
Auth and sessions

API keys and basic auth

Check opaque tokens with your own async lookup, and protect internal tools with HTTP Basic.

Open recipe
Public APIs

API keys with scopes

Issue keys that are stored only as hashes, authenticate them on every request, and limit what each key may do.

Open recipe
Auth and sessions

Cookies, sessions and CSRF

A browser login flow with server-side sessions, signed cookies and CSRF protection.

Open recipe
Auth and sessions

Sessions and broadcast on Redis

Share sessions and live updates across every instance with axeon-redis.

Open recipe
Public APIs

Rate limits and quotas

Per-client limits that differ by plan, daily quotas, standard RateLimit headers, and one limit shared by every instance.

Open recipe
Public APIs

Idempotency keys

Make POST requests safe to retry: a repeated Idempotency-Key gets the first response instead of running twice.

Open recipe
Public APIs

Signed webhooks

Send webhooks your customers can verify, and verify the ones you receive, with timestamps and secret rotation.

Open recipe
Multi-tenant apps

Host-based routing and custom domains

Serve storefronts from subdomains and customers' own domains, and keep the admin app on its own host.

Open recipe
Multi-tenant apps

Tenant-scoped data

Make cross-tenant leaks impossible by default: queries without a tenant fail instead of returning everyone's rows.

Open recipe
Data and storage

Configuration from the environment

Load typed settings from environment variables and a .env file, with every problem reported at once.

Open recipe
Data and storage

A database with axeon-orm

Models, typed queries, migrations and pagination on SQLite or PostgreSQL, wired into Axeon errors.

Open recipe
Data and storage

Upserts, bulk writes and enums

Insert or update in one statement, load thousands of rows quickly, and store enums as text.

Open recipe
Data and storage

Keyset pagination and optimistic locking

Page through large tables at constant cost, and stop two editors from silently overwriting each other.

Open recipe
Data and storage

Full-text and vector search

Search text with PostgreSQL full-text, find similar items with pgvector, and combine both into one ranked list.

Open recipe
Data and storage

Background jobs

Durable jobs on PostgreSQL with retries, delays, unique keys and graceful shutdown.

Open recipe
Files and pages

Static files and single-page apps

Serve a directory with range requests and caching, and fall back to index.html for client-side routes.

Open recipe
Files and pages

HTML templates

Server-rendered pages with auto-escaping templates, layouts and form handling.

Open recipe
Files and pages

File uploads

Accept multipart uploads and stream them straight to disk, with a per-route size limit.

Open recipe
Files and pages

Safe document uploads

Cap each file, check its real type from the first bytes, and hash it while streaming to disk or any writer.

Open recipe
Realtime

Server-sent events

Push live updates to the browser over a plain HTTP response.

Open recipe
Realtime

Broadcast across instances

Publish a message once and stream it to every subscriber on every instance, with resume after a reconnect.

Open recipe
Realtime

WebSockets

Echo server and a broadcast chat room, using Tokio's broadcast channel.

Open recipe
Production

Production setup

Logging with request IDs, metrics, health checks, limits, timeouts and graceful shutdown.

Open recipe
Production

Handler timeouts

Cap how long any route may take, override it per route, and answer 503 instead of hanging.

Open recipe
Production

Application metrics

Counters, gauges and histograms on the same Prometheus endpoint as the HTTP metrics.

Open recipe
Production

Distributed tracing with OpenTelemetry

A span per request, trace context passed to other services, and export to any OTLP collector.

Open recipe
Production

Calling other services safely

An outbound HTTP client with SSRF protection, timeouts, retries and a circuit breaker.

Open recipe
Production

OpenAPI documentation

Describe your routes once and serve a validated OpenAPI 3.1 document for clients and docs.

Open recipe
Production

Testing your app

Call routes in-process, with no sockets and no ports, and assert on status, headers and body.

Open recipe
Production

Using tower middleware

Plug in any tower layer, including all of tower-http, and run Axeon as a tower Service.

Open recipe
Production

HTTPS and HTTP/2

Serve TLS directly with rustls and get HTTP/2 negotiated automatically.

Open recipe

Fast without the ceremony

Within spitting distance of the fastest Rust frameworks, and an order of magnitude ahead of Node.

FrameworkJSONPath paramp99 latencyMemory
actix-web 4207k req/s190k req/s5–9 ms10.6 MiB
axum 0.8195k req/s197k req/s2–3 ms8.5 MiB
Axeon176k req/s185k req/s2 ms8.9 MiB
Express 5 (8 workers)39k req/s45k req/s14–22 ms877 MiB

Apple M1, 128 keep-alive connections, best of three runs. Read the full methodology before drawing conclusions for your workload.

Ship your first endpoint in a minute.

1
Create a projectcargo new hello && cd hello
2
Add Axeoncargo add axeon
3
Paste a recipecargo run