The Tokio team is building Rails for Rust with Topcoat

Topcoat is a Rust full stack web framework from the Tokio team. It packs routing, HTML templates, client reactivity, and a component library into one crate. The parts that already work are good. The roadmap is the other half of the story: twenty planned features, none of them checked off.
Key Takeaways
- Topcoat packs routing, templates, and reactivity into a single Rust crate.
- It comes from the Tokio team, who built the engine most Rust servers use.
- A working page takes about ten lines of code.
- All twenty items on the project roadmap are still unchecked.
- There are no docs yet on how to deploy an app.
Why a Rust full stack web framework is a big deal
Building a web app in Rust has meant shopping for parts. You pick a server crate, a template engine, a routing pattern, a database layer, and an asset pipeline. Then you wire them together yourself.
The result is that no two Rust web projects look alike. Guides go stale, and every new hire has to learn a stack nobody else uses. Ruby has Rails, PHP has Laravel, and Python has Django, while Rust still has a parts bin.
Topcoat aims straight at that gap. It calls itself a modular, batteries-included framework built around simplicity and productivity. It also lives in the tokio-rs org, right next to the async runtime most Rust network software already runs on. This is the most credible attempt yet at a Rails for Rust. Carl Lerche, who created Tokio, wrote it with Julien Scholz.
Lerche gave the reason directly when the repository went public.
the main reason for Topcoat to exist is that many organizations are already using Rust for infrastructure-level or performance sensitive reasons and often just want to build a web app using the programming language they already use.
That framing sets a narrower bar. Topcoat only has to be good enough that a team already shipping Rust services never starts a second stack. Beating Next.js is beside the point.
What a Topcoat page looks like
Start-up is a single line. You build a router that discovers your pages, then hand it to the server.
use topcoat::{
Result,
router::{Router, RouterBuilderDiscoverExt, page},
view::{component, view},
};
#[tokio::main]
async fn main() {
topcoat::start(Router::builder().discover().build()).await.unwrap();
}
#[page("/")]
async fn home() -> Result {
view! {
<!DOCTYPE html>
<html>
<body>
hello(name: "World")
</body>
</html>
}
}
#[component]
async fn hello(name: &str) -> Result {
view! { <h1>"Hello, " (name) "!"</h1> }
}A page is an async function with a #[page("/")] attribute. A component is an async function with #[component]. It takes ordinary Rust arguments, and you call it from a template by name. The view! macro stays close to plain HTML, so there is no new template dialect to learn.
Routing can follow your module tree, so src/app/posts/id.rs serves /posts/{post_id}. Your file layout is your URL layout, which most web developers already know from other frameworks.
Setup is short but manual. The getting started guide
has you run cargo new, add the topcoat crate
and Tokio, then paste the snippet above. Then cargo install topcoat-cli gives you a topcoat binary. Its dev command watches your source, rebuilds, rebundles assets, and live-reloads the browser.
Because components render on the server, they can be async and hit the database directly. There’s no separate API layer to build. A #[memoize] attribute caches a call for one request, so three components asking for the same user trigger a single query.
Styling comes in the box too. The asset pipeline scans your compiled binary for asset! calls and serves each file under a content hash. Tailwind
support is a feature flag. Topcoat UI then copies shadcn/ui
style components straight into your project, so you edit them instead of fighting their config.
Reactivity without WebAssembly
Topcoat’s biggest departure from every other Rust web framework is that it doesn’t compile Rust to WebAssembly . Instead, a macro turns a small set of type-checked Rust expressions into JavaScript.
You declare a signal, then wrap browser-side logic in $(...). Topcoat runs it on the server for the first render. After that, the same code runs in the browser as plain JavaScript.
view! {
signal open = false;
// Runs entirely in the browser; no server round-trip.
<button @click=$(|_e| open.set(!open.get()))>"What is Topcoat?"</button>
<p :hidden=$(!open.get())>"A full-stack Rust framework."</p>
}When an update really does need the server, you mark a component as a #[shard]. Topcoat re-renders it server-side whenever one of its arguments changes, then swaps the fresh HTML into place. Search as you type
works without a client bundle or a hand-written endpoint.
The payoff is no wasm bundle and no client build step. The Tokio team is clear that this is a trade. For rich interfaces, the heavier frameworks are still the right call.
However, many applications do not require this level of interactivity. For those use cases, compiling to a separate target, worrying about bundle sizes and splitting, and serializing data across the client/server boundary become a burden.
| Framework | What runs in the browser | Best for |
|---|---|---|
| Topcoat | JavaScript compiled from Rust expressions | Server-rendered apps with light interactivity |
| Leptos | WebAssembly | Rich client apps, Next.js style |
| Dioxus | WebAssembly | Web, desktop, and mobile from one codebase |
| Axum | Nothing, it is a router | HTTP APIs and lower-level services |
| Loco | Nothing built in | Rails-style apps with an ORM and generators |
The reactivity runtime is early, and the team says so. If it doesn’t stretch far enough, Topcoat ships integrations for htmx , Alpine AJAX, and Datastar as escape hatches.
What is missing before you can ship
The README opens with a warning in bold: early-stage and experimental, expect breaking changes. The roadmap backs that up, with every checkbox still empty.
Authentication is the gap people notice first. Still, the picture is better than the roadmap makes it look. Cookies and sessions already ship, with signed and encrypted cookies, sliding expiry, and token rotation. The announcement post even shows the pattern the team recommends. A require_auth function guards the component from the inside, so you never have to trust that a middleware ran. The batteries are what’s absent, so you still write your own user model, password handling, and sign-in form.
Validations are absent too, which is an odd hole in a framework this focused on forms. Also unchecked: static export, pre-rendering, streaming server rendering, client-side navigation, prefetching, background jobs, translations, image resizing, sitemaps, Markdown, and OpenAPI endpoints. There’s no topcoat new command either, so every project starts from a bare cargo new.
Deployment catches most people by surprise. There’s still no documentation on how to deploy a Topcoat app. It sits on the roadmap as one more unchecked task.
Only two versions have ever been tagged, v0.4.0 and v0.5.0. The crate has been downloaded roughly 3,087 times from crates.io. Far more people are watching this than building with it.
The database story sits just outside the framework. Toasty
, the team’s async ORM, handles models and migrations, and the repository ships a toasty-todo example. Tighter integration is on the roadmap. Forms would then create and update records without you listing every field by hand.
One commenter on the Hacker News thread argued that the Tokio name is doing some of the work here.
I’m not sure that projects like Topcoat and something like their ORM is a great direction for the project, and worry that they will possibly gain outsized adoption in the community based on name recognition rather than merit.
Lerche’s answer was that both Topcoat and Toasty will likely be split out of the tokio-rs org. They live there mainly because it has more CI budget.
Who should try Topcoat now
Spend an afternoon on it if you write Rust and have wanted one obvious way to build a web app. The API docs cover every piece. The repo ships two dozen runnable examples, including sessions, WebSockets, and server-sent events.
It’s a good fit for internal tools, where a breaking change costs you a refactor rather than a customer. It also suits you if you want a say in the design. The roadmap openly asks for issues, and releases are landing fast. Sessions and email both started as roadmap items, and both now ship with docs.
Hold off if you are picking a stack for a business. Rails, Laravel, and Django remain the boring correct answers. Rolling your own auth on a foundation that warns you about breaking changes is the worst version of that job. Hold off too if you need a static site, because export and pre-rendering aren’t built yet.
Don’t compare it to Leptos or Dioxus and expect a match. Those target rich client apps compiled to WebAssembly. Topcoat is server-first with reactivity sprinkled on, closer in spirit to htmx than to React.
Once authentication and deployment docs land in the same release, Topcoat becomes a real option for production work.
Botmonster Tech