I've been building a Rust web framework called Toxi, built around Hyper, Tokio, and Tower, and I'm looking for an architectural/code review rather than general project feedback.
The main idea is to provide a batteries-included backend stack while keeping the individual components usable independently.
Architecture
The main application path is:
Application
│
├── Router
│
├── Middleware
│
└── Server
│
▼
Hyper accept loop
The high-level API is:
let mut app = Application::new(Config::load().unwrap());
app.router_mut().get("/", hello);
app.run().await;
Handlers are ordinary async functions:
async fn hello(_req: Request) -> Result<Response> {
Ok(Response::text("Hello, Toxi!"))
}
The application abstraction is optional. The router and server can also be used directly:
let mut router = Router::new();
router.get("/", hello);
Server::new(router)
.listen("127.0.0.1:3000".parse().unwrap())
.await;
Middleware can be composed around the router:
let router = app.into_router();
Server::new(Logger::new(router))
.listen(addr)
.await;
The server provides configuration for CORS, body limits and HTTP versions, with TLS and HTTP/3 behind feature flags.
The CLI provides development and process-management commands such as:
toxi dev
toxi serve
toxi serve --bin name --port 3000
toxi pm2 start
All of these paths eventually use the same Hyper-based server implementation.
One of the things I'd particularly like reviewed is whether the boundary between Application, Router, Middleware and Server is appropriate, or whether some of these abstractions should be combined or separated differently.
Framework structure
The facade crate provides the batteries-included framework, while the individual components are separate crates.
The current stack includes:
routing and HTTP server
Tower-compatible middleware
configuration
SQLx-based ORM and migrations
authentication and sessions
templates
WebSockets, SSE and pub/sub
background jobs and queues
caching
storage
mail
GraphQL
OpenAPI
testing utilities
CLI and project generation
For example:
#[derive(Model)]
struct User {
id: i64,
name: String,
email: String,
}
let users = User::query()
.filter_eq("name", "Alice")
.fetch_all(&db)
.await?;
The intention is that the facade provides the integrated experience, while users can depend on individual crates when they don't need the entire stack.
The design philosophy is roughly:
own the stack, but don't make the components inseparable.
Architectural questions
There are several areas where I'd particularly like criticism.
Router
The router is currently hand-written and uses compiled regular expressions for route matching.
I'm considering whether this is a reasonable implementation choice or whether a trie-based approach such as matchit would be a better fit.
I'd be interested in feedback based on actual routing workloads, not just benchmark numbers.
Error handling
The framework currently has a central Error enum for framework-level errors:
InternalServerError
NotFound
BadRequest
Unauthorized
Forbidden
Conflict
Validation
...
This makes response mapping straightforward, but some structured information, particularly validation errors, currently ends up represented as strings.
I'm unsure whether the ergonomics of one framework-level error type justify that tradeoff.
Crate boundaries
The crates are independently versioned rather than being maintained as one Cargo workspace.
That gives the components genuine crate-level independence, but coordinating API changes and releases across multiple repositories is more complicated.
I'd like opinions on whether this is a useful form of modularity or unnecessary operational complexity.
Framework scope
This is probably the largest architectural question.
A framework such as Axum primarily provides the HTTP layer and leaves the rest of the application stack to the ecosystem.
Toxi instead owns a larger set of backend components: ORM, authentication, queues, templates, mail, API tooling, and so on.
I'm interested in whether this approach makes sense in Rust, particularly from an API stability and maintenance perspective, or whether the framework would be better off remaining thinner and composing existing crates.
Current state
Toxi is currently in the 3.x series, with the crates published separately.
There are example applications covering things such as task boards, blogs, short links, TODOs, notifications and pastebins.
The core has tests and benchmarks covering routing, extractors, responses, middleware, database operations, authentication, caching, templates, queues and realtime.
There are also known unfinished areas. GraphQL currently uses a fixed schema rather than providing a fully extensible application schema, and the file-based plugin loader is not finished.
Performance
I've also done a basic local comparison using an Intel Core i5 with 8 GB RAM.
The test used release builds, 125 connections, a 30-second run, GET /json, a "Hello World" response, and 100% successful requests:
Toxi 40,812 req/s p99 8.60 ms
Warp 40,681 req/s p99 11.51 ms
Poem 40,359 req/s p99 8.44 ms
Loco 28,994 req/s p99 10.49 ms
Salvo 27,759 req/s p99 33.78 ms
Rocket 23,207 req/s p99 36.34 ms
I'm not presenting this as a framework ranking. The benchmark still needs better methodology around repetitions, warmup, exact software/hardware information and endpoint parity.
What I'd like reviewed
The main things I'd like someone to challenge are:
Is the Application → Router → Middleware → Server boundary sound?
Is the regex router implementation a reasonable choice?
Is the central Error type too broad?
Are the crate boundaries and independent versioning sensible?
Is owning this much of the backend stack a good architectural decision?
Are there API or abstraction decisions that are likely to become difficult to change later?
Are there places where I'm unnecessarily reinventing something that the Rust ecosystem already handles better?
I've been making most of these architectural decisions myself for quite a while, so I'm particularly interested in criticism from people who have worked on Rust web frameworks, routers, middleware, Hyper/Tokio services, or async libraries.
Project:
Toxi on GitHub
Examples:
Toxi applications
3 posts - 2 participants
Read full topic
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Does my lockfree stack impl look correct? | 0 | 6.06 | 05-10-2026 |
| 2 | Any thin wrapper around the Web Worker API? | 0 | 6.59 | 07-10-2026 |
| 3 | Thisversion: Keep schema history out of your application model | 0 | 7.06 | 05-10-2026 |
| 4 | Feedback wanted: compio-pool, a thread-per-core connection pool for !Send connections | 0 | 17.89 | 08-10-2026 |
| 5 | Type erasure and dyn lifetime in a NonNull/Box struct field | 0 | 8.55 | 04-10-2026 |
| 6 | Announcing Topcoat: a framework for building full-stack reactive web apps with Rust | 0 | 18.33 | 22-07-2026 |
| 7 | What's everyone working on this week (41/2026)? | 0 | 20.34 | 06-10-2026 |
| 8 | Calling static C++ method from Rust | 0 | 9.94 | 04-10-2026 |
| 9 | I built a library for automatic callback encoding/decoding for Teloxide | 0 | 8.24 | 05-10-2026 |
| 10 | Limitations of `min_specialization` when specializing a generic implementation? | 0 | 9.38 | 04-10-2026 |