Oxide
A Rust-native, opinionated web framework that delivers a Spring Boot-like developer experience — without runtime reflection.
Built on top of Axum and Tokio, Oxide provides convention-first project structure, a clean chainable API, and standardized patterns for routing, configuration, middleware, and shared state.
Why Not Just Use Axum?
Axum is an incredible, high-performance routing library, but it is not a full framework.
When building production services with raw Axum, you repeatedly wire together the same boilerplate: configuring tracing subscribers, stacking Tower middleware correctly (CORS, timeouts, panic recovery, rate limiting), creating standardized JSON error envelopes, and managing dependency injection lifecycles.
Oxide removes that boilerplate and enforces correct conventions while keeping Axum-level performance.
The Killer Feature: Zero-Config Production APIs
Oxide ships with secure, production-tested defaults out of the box. You get automatic request logging, global panic recovery, standardized JSON success/error envelopes, and deterministic middleware ordering—all without writing a single line of configuration.
Axum vs. Oxide: The Boilerplate Difference
Raw Axum (30+ lines of exact middleware ordering & setup):
// A typical production Axum setup
let app = new
.route
// Middleware order is critical and easy to get wrong!
.layer
.layer
.layer
.layer
.with_state;
let listener = bind.await.unwrap;
serve.await.unwrap;
Oxide (5 lines, zero configuration for the same production readiness):
// Everything above is handled automatically and correctly.
new
.
.run;
Quickstart — Controller Style
use ;
use ;
;
Quickstart — Functional Style
use ;
use Serialize;
async
That gives you:
- A running HTTP server on
127.0.0.1:3000 - Configuration loaded from YAML + environment variables
- Shared state accessible in handlers via extractors
- Per-request logging (method, path, status, latency)
- Per-IP rate limiting (429 JSON on exceeded)
- CORS headers for cross-origin requests
- Request timeout enforcement (408 JSON on timeout)
- Graceful shutdown on Ctrl+C / SIGTERM
- Standardized JSON response envelopes
CLI (oxide)
Scaffold apps and generate controllers without boilerplate:
&&
From the Oxide repo, oxide test runs the full workspace test suite; oxide bench runs Criterion benchmarks plus the load-test example. See docs/cli.md for all commands and flags.
Project Structure
Oxide/
├── Cargo.toml # Workspace root
├── app.yaml # Application config
│
├── oxide_framework_core/ # Framework library
│ ├── src/
│ │ ├── lib.rs # Public API exports
│ │ ├── app.rs # App builder + server lifecycle
│ │ ├── router.rs # OxideRouter, Method enum
│ │ ├── response.rs # ApiResponse, JSON envelopes
│ │ ├── config.rs # AppConfig, YAML + env loading
│ │ ├── state.rs # AppState, TypeMap (shared state)
│ │ ├── extract.rs # Config, Data<T> extractors
│ │ ├── middleware.rs # Request logger, state injection layer
│ │ └── logging.rs # tracing-subscriber init
│ └── examples/
│ └── hello.rs # Full working example
│
├── oxide_framework_macros/ # Proc-macro crate (#[controller], route attrs)
└── oxide_cli/ # `oxide` CLI — scaffold, generate, run, test, bench
Public API at a Glance
| Export | Description |
|---|---|
App |
Builder for creating and running an Oxide application |
#[controller] |
Proc-macro: turns an impl block into a routable controller |
Controller |
Trait generated by #[controller] (also usable manually) |
OxideRouter |
Standalone router for modular route groups |
Method |
Enum: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS |
ApiResponse<T> |
Standardized JSON response with success/error envelopes |
AppConfig |
Configuration struct (YAML + env vars) |
AppState |
Shared state container (config + user extensions) |
Config |
Extractor for AppConfig in handlers |
Data<T> |
Extractor for user-provided state in handlers |
Inject<T> |
Alias for Data<T>, reads naturally in controller methods |
AuthConfig / App::auth |
HS256 JWT from Authorization: Bearer and/or a session cookie |
AuthClaims |
Decoded JWT subject + roles (in request extensions) |
Authenticated, OptionalAuth |
Extractors for logged-in / optional identity |
RequireRole<R>, RoleName |
Role guard (403 when role missing) |
encode_token |
Mint a JWT for login handlers / tests |
Json |
Re-export of axum::Json for request/response bodies |
Path |
Re-export of axum::extract::Path for path parameters |
StatusCode |
Re-export of axum::http::StatusCode |
Documentation
- Getting Started — Setup, first app, running the server
- Routing — Methods, nesting, merging, path parameters
- Responses — ApiResponse, JSON envelopes, error handling
- Configuration — YAML files, environment variables, defaults
- State Management — Shared state, Config/Data extractors, thread safety
- Middleware — Request logging, middleware architecture, custom middleware
- Authentication — JWT, session cookies, role guards
- Architecture — Crate layout, data flow, design principles
- CLI —
oxide new,generate,run,test,bench
Dependencies
| Crate | Purpose |
|---|---|
axum 0.8 |
HTTP routing and handler framework |
tokio 1 |
Async runtime |
tower 0.5 |
Middleware layer/service abstractions |
tower-http 0.6 |
CORS, panic recovery |
syn 2 / quote 1 |
Proc-macro parsing and code generation |
serde / serde_json / serde_yaml |
Serialization and config parsing |
tracing / tracing-subscriber |
Structured logging |
Running the Example
Then:
# {"status":200,"data":{"text":"Hello from my-oxide-app!"}}
# {"status":200,"data":{"app_name":"my-oxide-app","total_users_created":0}}
# {"status":200,"data":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}
# {"status":201,"data":{"id":1,"name":"Charlie"}}
# {"status":200,"data":{"app_name":"my-oxide-app","total_users_created":1}}
Server logs:
INFO oxide_framework_core::app: Oxide server started name=my-oxide-app address=127.0.0.1:3000
INFO oxide_framework_core::middleware: request completed method=GET path=/ status=200 latency_ms=0
INFO oxide_framework_core::middleware: request completed method=POST path=/api/users status=201 latency_ms=0
INFO oxide_framework_core::middleware: request completed method=GET path=/api/users/0 status=404 latency_ms=0
License
MIT