~/posts/technology/topcoat-webentwicklung-pures-rust.md

Topcoat: Wie weit ist Webentwicklung in purem Rust 2026?Topcoat: How far has pure Rust web development come in 2026?

·technology·
#framework#fullstack#rust#web

Rust war lange vor allem eine Sprache für Systems Programming, performante Backends und Kommandozeilenprogramme. Wer eine komplette Webanwendung bauen wollte, landete meistens bei einer bekannten Kombination: Rust auf dem Server und JavaScript oder TypeScript im Browser.

Dieses Bild verändert sich.

Frameworks wie Axum, Leptos und Dioxus haben Rust immer weiter in Richtung Fullstack-Webentwicklung gebracht. Mit Topcoat ist nun ein weiteres, noch junges Framework dazugekommen, das einen besonders interessanten Ansatz verfolgt.

Topcoat möchte eine moderne Webanwendung möglichst weit in Rust abbilden: Routing, Server Side Rendering, Komponenten, Assets, Tailwind, Sessions und sogar clientseitige Reaktivität.

Besonders ungewöhnlich ist dabei die Runtime. Interaktive Ausdrücke werden als Rust geschrieben, aber Topcoat kann einen unterstützten Teil davon für den Browser in JavaScript übersetzen.

Das bedeutet: Rust schreiben, serverseitig rendern und trotzdem Interaktivität im Browser bekommen – ohne eine WASM-Anwendung daraus machen zu müssen.

Wie gut funktioniert das bereits? Und können wir damit tatsächlich eine kleine Web-App bauen?

Schauen wir es uns an.

Stand dieses Artikels: August 2026. Topcoat entwickelt sich schnell. Die hier beschriebenen APIs orientieren sich an Topcoat 0.5.0 und der zu diesem Zeitpunkt aktuellen offiziellen Dokumentation. Das Projekt bezeichnet sich selbst weiterhin als "early-stage and experimental" und warnt ausdrücklich vor Breaking Changes.

Topcoat Logo

Was ist Topcoat?

Topcoat bezeichnet sich selbst als:

"The full full-stack framework for Rust"

Das Framework verfolgt einen "batteries included"-Ansatz. Statt lediglich einen HTTP-Router bereitzustellen und den Rest dem Entwickler zu überlassen, versucht Topcoat einen größeren Teil des Web-Stacks abzudecken.

Zum aktuellen Funktionsumfang beziehungsweise zur dokumentierten Architektur gehören unter anderem:

  • Server Side Rendering
  • asynchrone Komponenten
  • Routing
  • module-basiertes Routing
  • Assets
  • Web Fonts und Icons
  • Tailwind-Integration
  • Cookies
  • Sessions
  • Mail
  • clientseitige Reaktivität
  • serverseitig aktualisierte Shards
  • Procedures für Serverfunktionen aus dem Browser
  • eine eigene UI-Komponentenbibliothek
  • Integrationen für htmx, Alpine AJAX und Datastar

Das klingt deutlich mehr nach einem Fullstack-Framework wie Rails oder Laravel als nach einer kleinen Rust-Web-Library.

Allerdings ist eine Einschränkung wichtig: Topcoat ist noch jung.

Die Entwickler bezeichnen das Framework ausdrücklich als experimentell und rechnen mit Breaking Changes. Für ein langfristig stabiles Produktionsprojekt sollte man das derzeit berücksichtigen.

Was macht Topcoat anders?

Interessant wird Topcoat vor allem durch die Kombination aus Server Side Rendering und selektiver Client-Reaktivität.

Das Grundprinzip lautet:

Rust
  |
  v
Topcoat-Komponenten
  |
  v
Server Side Rendering
  |
  +------> HTML an den Browser
  |
  +------> unterstützte reaktive Ausdrücke
              |
              v
          JavaScript

Die Anwendung wird also nicht einfach vollständig als WebAssembly in den Browser geladen.

Topcoat rendert das Markup zunächst auf dem Server.

Komponenten sind dabei asynchrone Rust-Funktionen. Sie können deshalb serverseitige Arbeit erledigen und beispielsweise Daten laden, bevor HTML erzeugt wird.

Für Interaktivität besitzt Topcoat anschließend eine eigene Runtime.

Und genau dort wird es ungewöhnlich.

Reaktivität ohne WebAssembly

Nehmen wir ein minimales Beispiel aus dem Konzept von Topcoat:

view! {
    signal open = false;

    <button @click=$(|_e| open.set(!open.get()))>
        "Details anzeigen"
    </button>

    <p :hidden=$(!open.get())>
        "Dieser Inhalt ist reaktiv."
    </p>
}

Wir definieren zunächst einen Zustand:

signal open = false;

Anschließend verändern wir ihn bei einem Klick:

@click=$(|_e| open.set(!open.get()))

Und schließlich hängt ein HTML-Attribut davon ab:

:hidden=$(!open.get())

Wer React, Vue, Solid oder Svelte kennt, dürfte die grundlegende Idee sofort verstehen.

Der ungewöhnliche Teil steckt in $().

Ein solcher Ausdruck ist Rust-Code, der typgeprüft wird. Topcoat kann ihn beim initialen Rendern auf dem Server auswerten und gleichzeitig in JavaScript übersetzen, damit er im Browser erneut ausgeführt werden kann.

Dafür wird kein WASM-Bundle benötigt.

Und laut Topcoat ist dafür auch kein separater Client-Build-Step notwendig.

Bedeutet "pures Rust", dass kein JavaScript mehr existiert?

Nein.

Das ist eine wichtige Unterscheidung.

Als Entwickler können wir bestimmte Interaktionen in Rust formulieren. Im Browser muss diese Logik aber weiterhin in einer Sprache beziehungsweise Laufzeit ausgeführt werden, die der Browser versteht.

Topcoat löst dieses Problem nicht dadurch, dass plötzlich ein Browser Rust nativ ausführt.

Stattdessen übersetzt die Topcoat-Runtime unterstützte Rust-Ausdrücke nach JavaScript.

"Pures Rust" beschreibt deshalb eher die Developer Experience und den Anwendungscode, nicht zwingend die tatsächlich im Browser ausgeführte Sprache.

Das ist ein wichtiger Unterschied zu Frameworks, die Rust über WebAssembly in den Browser bringen.

Praxis: Unsere erste Topcoat-App

Genug Theorie.

Wir bauen eine kleine Anwendung, an der wir drei Dinge ausprobieren:

  1. Server Side Rendering
  2. Rust-Komponenten
  3. clientseitige Reaktivität

Wir halten das Projekt absichtlich klein, damit man erkennen kann, welche Teile Topcoat tatsächlich übernimmt.

Projekt anlegen

Voraussetzung ist eine funktionierende Rust-Installation mit Cargo.

Ein neues Rust-Projekt lässt sich zunächst ganz normal erstellen:

cargo new topcoat-demo
cd topcoat-demo

Topcoat befindet sich allerdings in schneller Entwicklung. Die offiziellen Getting-Started-Anweisungen sollten deshalb vor dem Nachbauen noch einmal geprüft werden, insbesondere für CLI-Installation und Features.

Für diesen Artikel orientieren wir den Anwendungscode an Topcoat 0.5.0.

Unsere minimale Struktur bleibt zunächst:

topcoat-demo/
├── Cargo.toml
└── src/
    └── main.rs

Der minimale Topcoat-Server

Eine minimale Topcoat-Anwendung sieht nach der aktuellen Dokumentation so aus:

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>
    }
}

Hier passieren bereits mehrere interessante Dinge.

#[page("/")] definiert eine Page für /.

Unsere Page ist dabei keine besondere Template-Datei, sondern eine normale asynchrone Rust-Funktion.

#[page("/")]
async fn home() -> Result

HTML entsteht anschließend innerhalb des view!-Makros.

Noch interessanter ist unsere Komponente:

#[component]
async fn hello(name: &str) -> Result

Auch sie ist eine asynchrone Rust-Funktion.

Die Komponente können wir anschließend innerhalb des Views aufrufen:

hello(name: "World")

Damit haben wir bereits Routing, SSR und Komponenten innerhalb eines Rust-Programms.

Unsere App bekommt eine richtige Komponente

Bauen wir daraus etwas Interessanteres.

Unsere Startseite ruft eine eigene App-Komponente auf:

#[page("/")]
async fn home() -> Result {
    view! {
        <!DOCTYPE html>
        <html lang="de">
            <head>
                <meta charset="utf-8">
                <meta
                    name="viewport"
                    content="width=device-width, initial-scale=1"
                >
                <title>"Meine Topcoat App"</title>
            </head>

            <body>
                app()
            </body>
        </html>
    }
}

Jetzt ergänzen wir:

#[component]
async fn app() -> Result {
    view! {
        <main>
            <h1>"Rust Web Playground"</h1>

            <p>
                "Diese Seite wird mit Rust und Topcoat gerendert."
            </p>

            rust_info()
        </main>
    }
}

Und schließlich unsere erste interaktive Komponente:

#[component]
async fn rust_info() -> Result {
    view! {
        signal open = false;

        <section>
            <button
                @click=$(|_event| open.set(!open.get()))
            >
                "Warum Rust im Web?"
            </button>

            <div :hidden=$(!open.get())>
                <h2>"Fullstack ohne klassischen JS-Stack"</h2>

                <p>
                    "Dieser Bereich lässt sich interaktiv ein- und ausblenden."
                </p>
            </div>
        </section>
    }
}

Damit haben wir eine kleine interaktive Anwendung.

Das Bemerkenswerte daran ist nicht der Button.

Das Bemerkenswerte ist, was wir dafür nicht geschrieben haben.

Wir haben keinen separaten JavaScript-Event-Handler erstellt.

Wir haben keine React-Komponente angelegt.

Wir haben keine JSON-API gebaut.

Und wir haben kein WebAssembly-Bundle erzeugt.

Der Zustand wird innerhalb unseres Rust-Views definiert.

Rust-Control-Flow im HTML

Topcoat versucht auch beim Templating, möglichst nah an normalem Rust zu bleiben.

Nehmen wir an, unsere App soll einige Technologien anzeigen:

#[component]
async fn stack() -> Result {
    let technologies = [
        "Rust",
        "Topcoat",
        "Tokio",
        "HTML",
    ];

    view! {
        <section>
            <h2>"Unser Stack"</h2>

            <ul>
                for technology in technologies {
                    <li>(technology)</li>
                }
            </ul>
        </section>
    }
}

Wir benötigen keine zusätzliche Template-Syntax wie:

{% for %}

oder:

v-for

Stattdessen verwenden wir normalen Rust-Control-Flow:

for technology in technologies {
    <li>(technology)</li>
}

Topcoat unterstützt dieses Prinzip auch für Bedingungen und bedingte Attribute.

Dadurch fühlt sich das Template weniger wie eine zweite Sprache an.

Jetzt wird es interessant: Wann muss der Server wieder ran?

Unser Toggle-Button benötigt keinen neuen Server-Request.

Aber reale Anwendungen bestehen natürlich nicht nur aus Buttons, die Elemente verstecken.

Nehmen wir eine Produktsuche.

Der Benutzer tippt:

rust

und unsere Anwendung soll passende Produkte aus einer Datenbank laden.

Jetzt brauchen wir den Server.

Topcoat besitzt dafür das Konzept der Shards.

Das grundlegende, von Topcoat dokumentierte Muster sieht so aus:

#[component]
async fn search() -> Result {
    view! {
        signal query = String::new();

        <input
            @input=$(|e: Event| query.set(e.target.value))
        >

        search_results(query: $(query.get()))
    }
}

Unsere Eingabe aktualisiert das Signal query.

Jetzt kommt der interessante Teil:

search_results(query: $(query.get()))

search_results kann als Shard definiert werden:

#[shard]
async fn search_results(cx: &Cx, query: String) -> Result {
    view! {
        <ul>
            for product in search_products(cx, &query).await? {
                <li>(product.name)</li>
            }
        </ul>
    }
}

Die Funktion search_products ist hier bewusst nur ein Platzhalter für unsere eigene Serverlogik.

Dort könnten wir beispielsweise SQLx, SeaORM oder einen anderen Datenbank-Layer verwenden.

Das wichtige Prinzip lautet:

Benutzer tippt
      |
      v
Signal verändert sich
      |
      v
Shard benötigt neue Daten
      |
      v
Request an Topcoat
      |
      v
Rust-Code auf dem Server
      |
      v
Datenbank
      |
      v
neues HTML
      |
      v
bestehende Seite wird aktualisiert

Topcoat rendert den Shard erneut auf dem Server und tauscht das entsprechende HTML im Browser aus.

Damit entsteht eine interessante Alternative zur klassischen SPA-Architektur.

Der klassische Fullstack-Weg

In einer typischen React-plus-Rust-Anwendung könnte eine Produktsuche ungefähr so aufgebaut sein:

React Component
      |
      v
fetch("/api/products?q=rust")
      |
      v
Rust API Handler
      |
      v
Datenbank
      |
      v
JSON
      |
      v
TypeScript
      |
      v
React State
      |
      v
JSX
      |
      v
DOM

Das ist nicht grundsätzlich schlecht.

Bei großen SPAs kann diese Trennung sogar sehr sinnvoll sein.

Aber sie erzeugt zusätzliche Schichten.

Wir benötigen möglicherweise:

  • API-Endpunkte
  • Request- und Response-Typen
  • Serialisierung
  • TypeScript-Typen
  • Fetch-Logik
  • Client-State
  • Fehlerbehandlung auf beiden Seiten
  • Rendering im Frontend

Topcoat stellt die Frage:

Was wäre, wenn der Server stattdessen einfach das neue HTML liefert?

Dann sieht die Architektur eher so aus:

Topcoat Component
      |
      v
Rust Server
      |
      v
Datenbank
      |
      v
HTML
      |
      v
Browser

Für viele klassische Webanwendungen ist das eine ziemlich attraktive Idee.

Und wenn der Browser eine Serverfunktion aufrufen soll?

Shards sind nicht das einzige Werkzeug der Runtime.

Topcoat dokumentiert inzwischen auch Procedures.

Dabei handelt es sich um asynchrone Serverfunktionen, die vom Browser aufgerufen werden können.

Das erweitert den möglichen Einsatzbereich erheblich.

Eine Anwendung muss also nicht zwangsläufig für jede Interaktion eine klassische REST-API definieren.

Damit bewegt sich Topcoat in eine Richtung, die wir auch bei anderen modernen Fullstack-Frameworks sehen: Die harte Trennung zwischen "Frontend-Code" und "Backend-Code" wird kleiner.

Routing kann sogar aus der Modulstruktur entstehen

Ein weiteres interessantes Feature ist module-basiertes Routing.

Topcoat kann die Route-Struktur optional aus den Rust-Modulen ableiten.

Eine Anwendung könnte beispielsweise so aufgebaut sein:

src/
├── app.rs
└── app/
    ├── about.rs
    ├── posts.rs
    ├── posts/
    │   └── id.rs
    └── api/
        └── health.rs

Daraus können sinngemäß folgende Routen entstehen:

/                 -> app.rs
/about            -> about.rs
/posts            -> posts.rs
/posts/{post_id}  -> posts/id.rs
/api/health       -> API Route

Das erinnert stärker an moderne Meta-Frameworks aus dem JavaScript-Ökosystem als an klassische Rust-Router.

Man muss dieses Routing-Modell nicht verwenden. Topcoat unterstützt auch explizit definierte Pages und Router.

Aber es zeigt, welchen Anspruch das Projekt verfolgt.

Topcoat möchte nicht nur HTTP-Requests verarbeiten.

Es möchte die Struktur einer kompletten Webanwendung definieren.

Assets gehören ebenfalls zum Framework

Auch statische Assets sind Teil des Konzepts.

Topcoat stellt dafür asset! bereit.

Ein Bild kann beispielsweise als Asset deklariert werden:

const FERRIS: Asset = asset!("./ferris.png");

und anschließend im View verwendet werden:

view! {
    <img src=(FERRIS)>
}

Der Bundler kann die Asset-Deklarationen im kompilierten Binary finden, die Dateien in das Asset-Verzeichnis kopieren und sie über content-basierte URLs ausliefern.

Auch Web Fonts und Icons sind Teil des Asset-Systems.

Das ist ein gutes Beispiel dafür, warum Topcoat sich als "batteries included" bezeichnet.

Tailwind ohne separaten Node-Stack

Topcoat besitzt außerdem eine Integration für Tailwind CSS.

Mit aktiviertem tailwind-Feature kann das Stylesheet über Topcoat eingebunden werden:

view! {
    <link
        rel="stylesheet"
        href=(topcoat::tailwind::stylesheet!())
    >
}

Laut aktueller Dokumentation ist Tailwind dabei in die Asset-Pipeline integriert und benötigt keinen separaten Node-basierten Tailwind-Build.

Damit wird die Vorstellung einer weitgehend Rust-zentrierten Webanwendung noch realistischer.

Der Stack kann beispielsweise so aussehen:

Sprache
└── Rust

Async Runtime
└── Tokio

Web Framework
└── Topcoat

Templates
└── view!

Client Reactivity
└── Topcoat Runtime

Styling
└── Tailwind

Datenbank
└── SQLx / SeaORM / Diesel

Deployment
└── Rust-Anwendung

Das ist schon erstaunlich weit entfernt von der Situation, in der Rust lediglich irgendwo hinter einer JSON-API sitzt.

Topcoat UI: Komponenten wie bei shadcn/ui

Interessant ist außerdem Topcoat UI.

Das Konzept ist von shadcn/ui inspiriert.

Anstatt eine UI-Bibliothek als unveränderliche Black Box einzubinden, werden Komponenten über die Topcoat CLI in das eigene Projekt kopiert.

Danach gehören sie praktisch zum eigenen Code und können angepasst werden.

Die Dokumentation zeigt beispielsweise Komponenten für Cards und Buttons.

Das ist gerade im Rust-Ökosystem interessant, weil eine der größten Stärken etablierter JavaScript-Frameworks bislang ihr gigantisches UI-Ökosystem ist.

Topcoat ist davon natürlich noch weit entfernt.

Aber die Richtung ist klar.

Wie "fullstack" ist Topcoat mittlerweile wirklich?

Schauen wir auf den derzeit dokumentierten Funktionsumfang.

BereichTopcoat
Server Side RenderingJa
KomponentenJa
Async ComponentsJa
RoutingJa
Module-basiertes RoutingJa
Client-ReaktivitätJa, experimentell
Rust-Ausdrücke im BrowserJa, begrenzter Sprachumfang
WebAssembly erforderlichNein
ShardsJa
ProceduresJa
AssetsJa
Web FontsJa
IconsJa
TailwindJa
CookiesJa
SessionsJa
MailJa
Topcoat UIJa
htmx-IntegrationJa
Alpine-AJAX-IntegrationJa
Datastar-IntegrationJa
Static ExportNoch Roadmap
Streaming SSR / SuspenseNoch Roadmap
Client-side NavigationNoch Roadmap
integrierte AuthenticationNoch Roadmap
Background JobsNoch Roadmap
Image OptimizationNoch Roadmap
LocalizationNoch Roadmap

Die Tabelle zeigt ziemlich gut, wo Topcoat momentan steht.

Es ist deutlich mehr als ein Experiment mit HTML-Templates.

Aber es ist auch noch kein fertiges Rust-Pendant zu Rails, Laravel oder Next.js.

Die größte Einschränkung: Die Runtime ist noch experimentell

Bei aller Begeisterung sollte man einen Punkt nicht unterschlagen.

Topcoat bezeichnet seine Runtime aktuell selbst als "highly experimental and fairly limited".

Derzeit wird nur ein begrenztes Vokabular an Typen und Methoden unterstützt.

Man sollte deshalb nicht davon ausgehen, dass beliebiger Rust-Code einfach in $() geschrieben und anschließend automatisch in JavaScript verwandelt werden kann.

Das wäre eine falsche Vorstellung.

Das Prinzip lautet eher:

bestimmter unterstützter Rust-Ausdruck
              |
              +---- Server-Auswertung
              |
              +---- JavaScript-Übersetzung

und nicht:

beliebiges Rust-Programm
              |
              v
        automatisch JavaScript

Gerade dieser Unterschied ist wichtig, wenn man Topcoat realistisch beurteilen möchte.

Ist Topcoat eine Alternative zu Leptos oder Dioxus?

Teilweise – aber die Philosophien unterscheiden sich.

Frameworks wie Leptos und Dioxus haben Rust bereits weit in die Fullstack- und Client-Webentwicklung gebracht.

Topcoat setzt jedoch einen anderen Schwerpunkt.

Statt eine umfangreiche Rust-Anwendung über WebAssembly in den Browser zu bringen, bleibt das Rendering stark serverorientiert.

Interaktivität wird gezielt ergänzt.

Das macht Topcoat besonders interessant für Anwendungen wie:

  • klassische SaaS-Produkte
  • Admin-Dashboards
  • interne Tools
  • CRUD-Anwendungen
  • Content-Plattformen
  • Shops
  • Formulare
  • serverzentrierte Business-Anwendungen

Bei einer extrem clientlastigen Anwendung – beispielsweise einem komplexen Grafikeditor im Browser – sieht die Rechnung möglicherweise anders aus.

Dort können WebAssembly oder ein klassisches JavaScript-Framework weiterhin die sinnvollere Architektur darstellen.

Ist Topcoat eine Alternative zu React?

Die interessantere Antwort lautet: Topcoat versucht teilweise, die Frage überflüssig zu machen.

React ist primär eine Client-UI-Library.

Topcoat denkt stärker vom Server aus.

Bei vielen Webanwendungen muss aber gar nicht die komplette Anwendung dauerhaft als JavaScript-State-Machine im Browser leben.

Nehmen wir ein Admin-Dashboard.

Der Benutzer:

  1. öffnet eine Seite,
  2. sieht Daten,
  3. filtert eine Tabelle,
  4. öffnet ein Formular,
  5. speichert Änderungen,
  6. bekommt aktualisiertes HTML.

Braucht diese Anwendung zwingend eine vollständige SPA-Architektur?

Nicht unbedingt.

Genau in diesem Bereich werden serverzentrierte Frameworks wieder interessant.

Topcoat verbindet diese alte Idee mit modernen Komponenten und Reaktivität.

Brauchen wir mit Topcoat überhaupt noch JavaScript?

Technisch: ja.

Topcoats Runtime übersetzt unterstützte reaktive Rust-Ausdrücke in JavaScript.

Aus Sicht des Anwendungsentwicklers lautet die Antwort aber zunehmend:

Vielleicht müssen wir JavaScript deutlich seltener selbst schreiben.

Das ist ein wichtiger Unterschied.

Topcoat versucht JavaScript nicht aus dem Browser zu entfernen.

Es versucht, JavaScript aus einem großen Teil unseres täglichen Anwendungscodes zu entfernen.

Und möglicherweise ist genau das der praktischere Ansatz.

Rust-Webentwicklung ist inzwischen erstaunlich komplett

Topcoat ist außerdem nur ein Teil eines deutlich größeren Ökosystems.

Rust besitzt heute Lösungen für praktisch alle grundlegenden Bereiche einer Webanwendung.

AufgabeBeispiele
Async RuntimeTokio
HTTP / BackendAxum, Actix Web
FullstackTopcoat, Leptos, Dioxus
DatenbankSQLx, Diesel, SeaORM
TemplatesAskama, Maud
WebAssemblywasm-bindgen, Leptos, Dioxus, Yew
SerialisierungSerde
MiddlewareTower
TLSrustls

Die Frage lautet deshalb inzwischen nicht mehr:

Kann Rust überhaupt Webentwicklung?

Natürlich kann es das.

Interessanter ist die Frage:

Kann Rust den größten Teil einer modernen Fullstack-Webanwendung abdecken, ohne dass wir zusätzlich ein separates JavaScript-Projekt pflegen müssen?

Topcoat zeigt, dass die Antwort darauf zunehmend ja lautet.

Warum diese Entwicklung spannend ist

Ein gemeinsamer Fullstack in Rust kann einige interessante Eigenschaften haben.

Wir verwenden dieselbe Sprache auf dem Server und für einen Teil unserer UI-Logik.

Wir verwenden dasselbe Typsystem.

Wir verwenden Cargo.

Wir verwenden dieselben Datenstrukturen und Bibliotheken dort, wo es die Architektur erlaubt.

Und wir reduzieren möglicherweise die Anzahl der Grenzen zwischen Frontend und Backend.

Statt:

Rust
↓
API
↓
JSON
↓
TypeScript
↓
React

können bestimmte Anwendungen näher an folgendes Modell rücken:

Rust
↓
Topcoat
↓
HTML + minimale Browser-Runtime

Weniger Schichten bedeuten nicht automatisch bessere Software.

Aber jede Schicht hat Kosten.

Topcoat stellt deshalb eine durchaus interessante Architekturfrage: Welche dieser Schichten brauchen wir für unsere konkrete Anwendung tatsächlich?

Ist Topcoat schon produktionsreif?

Hier sollte man aktuell vorsichtig sein.

Topcoat selbst bezeichnet das gesamte Projekt als "early-stage and experimental" und warnt vor Breaking Changes.

Auch mehrere wichtige Features befinden sich noch auf der Roadmap.

Wer heute ein langlebiges kommerzielles Produkt startet und eine über Jahre stabile API erwartet, sollte das berücksichtigen.

Für Experimente, Side Projects, interne Tools und Entwickler, die die Zukunft der Rust-Webentwicklung ausprobieren möchten, ist Topcoat dagegen ausgesprochen interessant.

Gerade weil das Framework noch jung ist, lässt sich momentan beobachten, welche Architekturentscheidungen sich durchsetzen.

Was noch fehlt

Die Roadmap ist ebenfalls aufschlussreich.

Zum Zeitpunkt dieses Artikels sind unter anderem folgende Themen noch geplant:

  • Static Export
  • mehr Runtime-Reaktivität
  • weitere Topcoat-UI-Komponenten
  • Validierungen
  • Localization
  • OpenAPI-Endpunkte
  • Sitemaps
  • Deployment-Dokumentation
  • Pre-Rendering statischer Seiten
  • Streaming SSR / Suspense
  • Client-side Navigation und Prefetching
  • WebTransport
  • Image Optimization
  • Markdown Support
  • einfachere Middleware
  • Authentication
  • Background Jobs
  • Islands

Gerade diese Liste zeigt, dass Topcoat noch einiges vor sich hat.

Sie zeigt aber gleichzeitig den Anspruch.

Das Ziel ist offensichtlich nicht nur ein weiteres Template-Framework.

Topcoat möchte ein vollständiges Webframework für Rust werden.

Fazit: Wie weit ist Webentwicklung in purem Rust 2026?

Erstaunlich weit.

Topcoat ist dafür ein gutes Beispiel.

Wir können heute eine servergerenderte Webanwendung schreiben, Komponenten als asynchrone Rust-Funktionen definieren, Rust-Control-Flow direkt im Markup verwenden, Assets verwalten, Tailwind integrieren, Sessions nutzen und sogar reaktive Client-Interaktionen in Rust formulieren.

Braucht der Browser dafür plötzlich kein JavaScript mehr?

Nein.

Topcoat übersetzt unterstützte reaktive Ausdrücke in JavaScript.

Brauchen wir WebAssembly?

Für Topcoats eigenes Reaktivitätsmodell nicht.

Brauchen wir zwingend React, Vue oder Svelte?

Für viele klassische Webanwendungen möglicherweise ebenfalls nicht.

Und genau das ist die interessante Erkenntnis.

Vor einigen Jahren war Rust im Web vor allem eine interessante Sprache für schnelle Backends.

Heute diskutieren wir darüber, ob eine komplette Webanwendung inklusive UI, Routing, SSR, Assets, Sessions und Client-Reaktivität innerhalb eines Rust-zentrierten Stacks entwickelt werden kann.

Topcoat ist noch experimentell und definitiv nicht fertig.

Aber vielleicht ist gerade das der spannendste Punkt an diesem Framework.

Topcoat zeigt nicht, dass JavaScript verschwunden ist.

Es zeigt, dass Rust inzwischen weit genug gekommen ist, dass JavaScript nicht mehr zwangsläufig das Zentrum jeder modernen Webanwendung sein muss.

Und das hätte vor einigen Jahren vermutlich noch deutlich unrealistischer geklungen.

Häufige Fragen zu Topcoat

Was ist Topcoat in Rust?

Topcoat ist ein experimentelles Fullstack-Webframework für Rust. Es kombiniert unter anderem Server Side Rendering, Komponenten, Routing, Assets und clientseitige Reaktivität in einem Rust-zentrierten Framework.

Benötigt Topcoat WebAssembly?

Für die eigene Topcoat-Runtime ist kein WASM-Bundle erforderlich. Unterstützte reaktive Rust-Ausdrücke werden stattdessen für den Browser in JavaScript übersetzt.

Kann Topcoat Rust direkt im Browser ausführen?

Nicht im Sinne einer nativen Rust-Laufzeit im Browser. Topcoat kann unterstützte Ausdrücke aus seiner Runtime nach JavaScript übersetzen. Beliebiger Rust-Code lässt sich derzeit nicht einfach im Browser ausführen.

Ist Topcoat bereits produktionsreif?

Topcoat bezeichnet sich selbst aktuell als "early-stage and experimental" und warnt vor Breaking Changes. Für langfristige Produktionsprojekte sollte man diesen Entwicklungsstand berücksichtigen.

Kann Topcoat eine Datenbank verwenden?

Ja. Topcoat-Komponenten sind serverseitige asynchrone Rust-Funktionen und können entsprechend serverseitige Datenbanklogik aufrufen. Die konkrete Datenbankbibliothek kann beispielsweise SQLx, Diesel oder SeaORM sein.

Was sind Topcoat Shards?

Shards sind Komponenten, die auf dem Server erneut gerendert werden können, wenn sich reaktive Argumente ändern. Das neue HTML wird anschließend in die bestehende Seite eingesetzt.

Was sind Topcoat Procedures?

Procedures sind asynchrone Serverfunktionen, die aus dem Browser aufgerufen werden können. Sie ergänzen das serverzentrierte Modell für Interaktionen, bei denen tatsächlich Serverlogik ausgeführt werden muss.

Ist Topcoat eine Alternative zu React?

Für serverzentrierte Anwendungen kann Topcoat Teile der Aufgaben übernehmen, für die sonst React oder ein ähnliches Frontend-Framework eingesetzt würde. Bei stark clientseitigen SPAs unterscheiden sich Architektur und Einsatzgebiet jedoch deutlich.

Unterstützt Topcoat Tailwind CSS?

Ja. Topcoat dokumentiert eine integrierte Tailwind-Unterstützung, die in die Asset-Pipeline eingebunden werden kann.

Kann man eine Webanwendung komplett in Rust schreiben?

Heute lässt sich ein sehr großer Teil einer Webanwendung in Rust umsetzen. Topcoat geht noch einen Schritt weiter, indem selbst bestimmte clientseitige Interaktionen als Rust-Ausdrücke geschrieben werden können. Im Browser werden diese unterstützten Ausdrücke allerdings in JavaScript ausgeführt.

Weiterführende Quellen

Dieser Artikel basiert auf dem Stand der offiziellen Dokumentation im August 2026. Da Topcoat ausdrücklich experimentell ist, sollte vor dem Nachbauen immer die aktuelle Dokumentation geprüft werden.

Topcoat: How far has pure Rust web development come in 2026?

Rust was long seen mainly as a language for systems programming, high-performance backends, and command-line tools. Anyone who wanted to build a complete web application usually ended up with a familiar combination: Rust on the server and JavaScript or TypeScript in the browser.

That picture is changing.

Frameworks such as Axum, Leptos, and Dioxus have pushed Rust further and further toward full-stack web development. With Topcoat, another young framework has now appeared that pursues a particularly interesting approach.

Topcoat wants to map a modern web application as far as possible in Rust: routing, server-side rendering, components, assets, Tailwind, sessions, and even client-side reactivity.

What is especially unusual is the runtime. Interactive expressions are written as Rust, but Topcoat can translate a supported subset of them into JavaScript for the browser.

That means: write Rust, render server-side, and still get interactivity in the browser—without having to turn it into a WASM application.

How well does that work already? And can we actually build a small web app with it?

Let's find out.

Status of this article: August 2026. Topcoat develops quickly. The APIs described here follow Topcoat 0.5.0 and the official documentation current at that time. The project still describes itself as “early-stage and experimental” and explicitly warns of breaking changes.

Topcoat Logo

What is Topcoat?

Topcoat describes itself as:

“The full full-stack framework for Rust”

The framework follows a “batteries included” approach. Instead of merely providing an HTTP router and leaving the rest to the developer, Topcoat tries to cover a larger part of the web stack.

The current feature set, or documented architecture, includes:

  • server-side rendering
  • async components
  • routing
  • module-based routing
  • assets
  • web fonts and icons
  • Tailwind integration
  • cookies
  • sessions
  • mail
  • client-side reactivity
  • server-updated shards
  • procedures for calling server functions from the browser
  • a UI component library
  • integrations for htmx, Alpine AJAX, and Datastar

That sounds much more like a full-stack framework such as Rails or Laravel than like a small Rust web library.

However, one limitation matters: Topcoat is still young.

The developers explicitly describe the framework as experimental and expect breaking changes. For a long-lived production project, that should be taken into account for now.

What makes Topcoat different?

Topcoat becomes interesting above all through the combination of server-side rendering and selective client reactivity.

The basic principle is:

Rust
  |
  v
Topcoat components
  |
  v
Server-side rendering
  |
  +------> HTML to the browser
  |
  +------> supported reactive expressions
              |
              v
          JavaScript

The application is therefore not simply loaded into the browser entirely as WebAssembly.

Topcoat first renders the markup on the server.

Components are asynchronous Rust functions. They can therefore do server-side work and, for example, load data before HTML is produced.

For interactivity, Topcoat then has its own runtime.

And that is exactly where it gets unusual.

Reactivity without WebAssembly

Let's take a minimal example from Topcoat's concept:

view! {
    signal open = false;

    <button @click=$(|_e| open.set(!open.get()))>
        "Details anzeigen"
    </button>

    <p :hidden=$(!open.get())>
        "Dieser Inhalt ist reaktiv."
    </p>
}

First we define a piece of state:

signal open = false;

Then we change it on a click:

@click=$(|_e| open.set(!open.get()))

And finally an HTML attribute depends on it:

:hidden=$(!open.get())

Anyone familiar with React, Vue, Solid, or Svelte will understand the basic idea immediately.

The unusual part is $().

Such an expression is Rust code that gets type-checked. Topcoat can evaluate it on the server during the initial render and at the same time translate it into JavaScript so that it can run again in the browser.

No WASM bundle is needed for that.

And according to Topcoat, no separate client build step is necessary either.

Does “pure Rust” mean JavaScript no longer exists?

No.

That is an important distinction.

As developers, we can formulate certain interactions in Rust. In the browser, that logic still has to run in a language or runtime that the browser understands.

Topcoat does not solve this by suddenly having a browser run native Rust.

Instead, the Topcoat runtime translates supported Rust expressions into JavaScript.

“Pure Rust” therefore describes the developer experience and the application code, not necessarily the language actually executed in the browser.

That is an important difference from frameworks that bring Rust into the browser via WebAssembly.

In practice: our first Topcoat app

Enough theory.

We build a small application with which we try out three things:

  1. server-side rendering
  2. Rust components
  3. client-side reactivity

We deliberately keep the project small so that it becomes clear which parts Topcoat actually takes over.

Creating the project

A working Rust installation with Cargo is a prerequisite.

A new Rust project can be created quite normally at first:

cargo new topcoat-demo
cd topcoat-demo

Topcoat is, however, developing quickly. The official getting-started instructions should therefore be checked again before reproducing this, especially for the CLI installation and features.

For this article, we orient the application code to Topcoat 0.5.0.

Our minimal structure initially remains:

topcoat-demo/
├── Cargo.toml
└── src/
    └── main.rs

The minimal Topcoat server

A minimal Topcoat application looks like this, according to the current documentation:

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>
    }
}

Several interesting things are already happening here.

#[page("/")] defines a page for /.

Our page is not a special template file, but an ordinary asynchronous Rust function:

#[page("/")]
async fn home() -> Result

HTML is then produced inside the view! macro.

Our component is even more interesting:

#[component]
async fn hello(name: &str) -> Result

It too is an asynchronous Rust function.

We can then call the component inside the view:

hello(name: "World")

With that, we already have routing, SSR, and components within one Rust program.

Our app gets a real component

Let's build something more interesting from it.

Our home page calls its own app component:

#[page("/")]
async fn home() -> Result {
    view! {
        <!DOCTYPE html>
        <html lang="de">
            <head>
                <meta charset="utf-8">
                <meta
                    name="viewport"
                    content="width=device-width, initial-scale=1"
                >
                <title>"Meine Topcoat App"</title>
            </head>

            <body>
                app()
            </body>
        </html>
    }
}

Now we add:

#[component]
async fn app() -> Result {
    view! {
        <main>
            <h1>"Rust Web Playground"</h1>

            <p>
                "Diese Seite wird mit Rust und Topcoat gerendert."
            </p>

            rust_info()
        </main>
    }
}

And finally our first interactive component:

#[component]
async fn rust_info() -> Result {
    view! {
        signal open = false;

        <section>
            <button
                @click=$(|_event| open.set(!open.get()))
            >
                "Warum Rust im Web?"
            </button>

            <div :hidden=$(!open.get())>
                <h2>"Fullstack ohne klassischen JS-Stack"</h2>

                <p>
                    "Dieser Bereich lässt sich interaktiv ein- und ausblenden."
                </p>
            </div>
        </section>
    }
}

With that, we have a small interactive application.

The remarkable thing is not the button.

The remarkable thing is what we did not have to write for it.

We did not create a separate JavaScript event handler.

We did not create a React component.

We did not build a JSON API.

And we did not generate a WebAssembly bundle.

The state is defined within our Rust view.

Rust control flow in the HTML

Topcoat also tries to stay as close to normal Rust as possible when templating.

Suppose our app should display some technologies:

#[component]
async fn stack() -> Result {
    let technologies = [
        "Rust",
        "Topcoat",
        "Tokio",
        "HTML",
    ];

    view! {
        <section>
            <h2>"Unser Stack"</h2>

            <ul>
                for technology in technologies {
                    <li>(technology)</li>
                }
            </ul>
        </section>
    }
}

We need no additional template syntax such as:

{% for %}

or:

v-for

Instead we use normal Rust control flow:

for technology in technologies {
    <li>(technology)</li>
}

Topcoat supports this principle for conditions and conditional attributes as well.

That makes the template feel less like a second language.

Now it gets interesting: when does the server have to get involved again?

Our toggle button needs no new server request.

But real applications naturally consist of more than buttons that hide elements.

Let's take a product search.

The user types:

rust

and our application should load matching products from a database.

Now we need the server.

Topcoat has the concept of shards for this.

The basic pattern documented by Topcoat looks like this:

#[component]
async fn search() -> Result {
    view! {
        signal query = String::new();

        <input
            @input=$(|e: Event| query.set(e.target.value))
        >

        search_results(query: $(query.get()))
    }
}

Our input updates the query signal.

Now comes the interesting part:

search_results(query: $(query.get()))

search_results can be defined as a shard:

#[shard]
async fn search_results(cx: &Cx, query: String) -> Result {
    view! {
        <ul>
            for product in search_products(cx, &query).await? {
                <li>(product.name)</li>
            }
        </ul>
    }
}

The function search_products is deliberately only a placeholder here for our own server logic.

There we could use SQLx, SeaORM, or another database layer, for example.

The important principle is:

user types
      |
      v
signal changes
      |
      v
shard needs new data
      |
      v
request to Topcoat
      |
      v
Rust code on the server
      |
      v
database
      |
      v
new HTML
      |
      v
existing page is updated

Topcoat re-renders the shard on the server and swaps the corresponding HTML in the browser.

That creates an interesting alternative to the classic SPA architecture.

The classic full-stack path

In a typical React-plus-Rust application, a product search could be structured roughly like this:

React Component
      |
      v
fetch("/api/products?q=rust")
      |
      v
Rust API Handler
      |
      v
database
      |
      v
JSON
      |
      v
TypeScript
      |
      v
React state
      |
      v
JSX
      |
      v
DOM

That is not fundamentally bad.

For large SPAs, this separation can even make a lot of sense.

But it creates additional layers.

We may need:

  • API endpoints
  • request and response types
  • serialization
  • TypeScript types
  • fetch logic
  • client state
  • error handling on both sides
  • frontend rendering

Topcoat asks the question:

What if the server instead simply delivered the new HTML?

Then the architecture looks more like this:

Topcoat Component
      |
      v
Rust Server
      |
      v
database
      |
      v
HTML
      |
      v
browser

For many classic web applications, that is a fairly attractive idea.

And when the browser should call a server function?

Shards are not the only tool of the runtime.

Topcoat now also documents procedures.

These are asynchronous server functions that can be called from the browser.

That considerably extends the possible area of use.

An application therefore does not necessarily have to define a classic REST API for every interaction.

With that, Topcoat moves in a direction we also see in other modern full-stack frameworks: the hard separation between “frontend code” and “backend code” becomes smaller.

Routing can even emerge from the module structure

Another interesting feature is module-based routing.

Topcoat can optionally derive the route structure from the Rust modules.

An application could, for example, be structured like this:

src/
├── app.rs
└── app/
    ├── about.rs
    ├── posts.rs
    ├── posts/
    │   └── id.rs
    └── api/
        └── health.rs

From this, the following routes can roughly emerge:

/                 -> app.rs
/about            -> about.rs
/posts            -> posts.rs
/posts/{post_id}  -> posts/id.rs
/api/health       -> API route

That resembles modern meta-frameworks from the JavaScript ecosystem more than classic Rust routers.

You do not have to use this routing model. Topcoat also supports explicitly defined pages and routers.

But it shows what claim the project pursues.

Topcoat wants not only to process HTTP requests.

It wants to define the structure of a complete web application.

Assets also belong to the framework

Static assets are likewise part of the concept.

Topcoat provides asset! for that.

An image can, for example, be declared as an asset:

const FERRIS: Asset = asset!("./ferris.png");

and then used in the view:

view! {
    <img src=(FERRIS)>
}

The bundler can find the asset declarations in the compiled binary, copy the files into the asset directory, and serve them via content-based URLs.

Web fonts and icons are also part of the asset system.

That is a good example of why Topcoat calls itself “batteries included”.

Tailwind without a separate Node stack

Topcoat also has an integration for Tailwind CSS.

With the tailwind feature enabled, the stylesheet can be included via Topcoat:

view! {
    <link
        rel="stylesheet"
        href=(topcoat::tailwind::stylesheet!())
    >
}

According to the current documentation, Tailwind is integrated into the asset pipeline and needs no separate Node-based Tailwind build.

That makes the idea of a largely Rust-centred web application even more realistic.

The stack can, for example, look like this:

Language
└── Rust

Async runtime
└── Tokio

Web framework
└── Topcoat

Templates
└── view!

Client reactivity
└── Topcoat runtime

Styling
└── Tailwind

Database
└── SQLx / SeaORM / Diesel

Deployment
└── Rust application

That is already astonishingly far from the situation in which Rust merely sits somewhere behind a JSON API.

Topcoat UI: components like shadcn/ui

Topcoat UI is also interesting.

The concept is inspired by shadcn/ui.

Instead of including a UI library as an immutable black box, components are copied into your own project via the Topcoat CLI.

After that, they practically belong to your own code and can be adjusted.

The documentation shows components for cards and buttons, for example.

That is interesting precisely in the Rust ecosystem, because one of the greatest strengths of established JavaScript frameworks so far has been their gigantic UI ecosystem.

Topcoat is, of course, still far from that.

But the direction is clear.

How “fullstack” is Topcoat really by now?

Let's look at the currently documented feature set.

AreaTopcoat
Server-side renderingYes
ComponentsYes
Async componentsYes
RoutingYes
Module-based routingYes
Client reactivityYes, experimental
Rust expressions in the browserYes, limited language subset
WebAssembly requiredNo
ShardsYes
ProceduresYes
AssetsYes
Web fontsYes
IconsYes
TailwindYes
CookiesYes
SessionsYes
MailYes
Topcoat UIYes
htmx integrationYes
Alpine AJAX integrationYes
Datastar integrationYes
Static exportStill roadmap
Streaming SSR / SuspenseStill roadmap
Client-side navigationStill roadmap
Integrated authenticationStill roadmap
Background jobsStill roadmap
Image optimizationStill roadmap
LocalizationStill roadmap

The table shows quite well where Topcoat currently stands.

It is clearly more than an experiment with HTML templates.

But it is also not yet a finished Rust counterpart to Rails, Laravel, or Next.js.

The biggest limitation: the runtime is still experimental

For all the enthusiasm, one point should not be glossed over.

Topcoat currently describes its runtime itself as “highly experimental and fairly limited”.

Currently only a limited vocabulary of types and methods is supported.

You should therefore not assume that arbitrary Rust code can simply be written in $() and then automatically turned into JavaScript.

That would be a misconception.

The principle is more like:

specific supported Rust expression
              |
              +---- server evaluation
              |
              +---- JavaScript translation

and not:

arbitrary Rust program
              |
              v
        automatically JavaScript

Precisely this difference matters when you want to judge Topcoat realistically.

Is Topcoat an alternative to Leptos or Dioxus?

Partly—but the philosophies differ.

Frameworks such as Leptos and Dioxus have already pushed Rust far into full-stack and client web development.

Topcoat, however, sets a different emphasis.

Instead of bringing an extensive Rust application into the browser via WebAssembly, rendering stays strongly server-oriented.

Interactivity is added deliberately.

That makes Topcoat especially interesting for applications such as:

  • classic SaaS products
  • admin dashboards
  • internal tools
  • CRUD applications
  • content platforms
  • shops
  • forms
  • server-centred business applications

For an extremely client-heavy application—for example, a complex graphics editor in the browser—the calculation may look different.

There, WebAssembly or a classic JavaScript framework can continue to be the more sensible architecture.

Is Topcoat an alternative to React?

The more interesting answer is: Topcoat partly tries to make the question obsolete.

React is primarily a client UI library.

Topcoat thinks more from the server.

For many web applications, however, the entire application does not need to live permanently in the browser as a JavaScript state machine.

Take an admin dashboard.

The user:

  1. opens a page,
  2. sees data,
  3. filters a table,
  4. opens a form,
  5. saves changes,
  6. receives updated HTML.

Does this application necessarily need a full SPA architecture?

Not necessarily.

It is precisely in this area that server-centred frameworks become interesting again.

Topcoat connects this old idea with modern components and reactivity.

Do we still need JavaScript with Topcoat at all?

Technically: yes.

Topcoat's runtime translates supported reactive Rust expressions into JavaScript.

From the application developer's perspective, the answer is, however, increasingly:

Perhaps we have to write JavaScript significantly less often ourselves.

That is an important difference.

Topcoat does not try to remove JavaScript from the browser.

It tries to remove JavaScript from a large part of our daily application code.

And perhaps that is exactly the more practical approach.

Rust web development is astonishingly complete by now

Topcoat is also only part of a much larger ecosystem.

Rust today has solutions for practically all fundamental areas of a web application.

TaskExamples
Async runtimeTokio
HTTP / backendAxum, Actix Web
FullstackTopcoat, Leptos, Dioxus
DatabaseSQLx, Diesel, SeaORM
TemplatesAskama, Maud
WebAssemblywasm-bindgen, Leptos, Dioxus, Yew
SerializationSerde
MiddlewareTower
TLSrustls

The question is therefore no longer:

Can Rust do web development at all?

Of course it can.

The more interesting question is:

Can Rust cover the greatest part of a modern full-stack web application without us having to maintain an additional separate JavaScript project?

Topcoat shows that the answer to that is increasingly yes.

Why this development is exciting

A shared full stack in Rust can have some interesting properties.

We use the same language on the server and for part of our UI logic.

We use the same type system.

We use Cargo.

We use the same data structures and libraries where the architecture allows it.

And we possibly reduce the number of boundaries between frontend and backend.

Instead of:

Rust
↓
API
↓
JSON
↓
TypeScript
↓
React

certain applications can move closer to the following model:

Rust
↓
Topcoat
↓
HTML + minimal browser runtime

Fewer layers do not automatically mean better software.

But every layer has costs.

Topcoat therefore poses a quite interesting architecture question: Which of these layers do we actually need for our concrete application?

Is Topcoat production-ready yet?

Here one should currently be cautious.

Topcoat itself describes the entire project as “early-stage and experimental” and warns of breaking changes.

Several important features are also still on the roadmap.

Anyone starting a long-lived commercial product today and expecting an API stable over years should take that into account.

For experiments, side projects, internal tools, and developers who want to try out the future of Rust web development, Topcoat is, by contrast, extremely interesting.

Precisely because the framework is still young, one can currently observe which architecture decisions win out.

What is still missing

The roadmap is also revealing.

At the time of this article, the following topics are, among others, still planned:

  • static export
  • more runtime reactivity
  • more Topcoat UI components
  • validation
  • localization
  • OpenAPI endpoints
  • sitemaps
  • deployment documentation
  • pre-rendering of static pages
  • streaming SSR / Suspense
  • client-side navigation and prefetching
  • WebTransport
  • image optimization
  • Markdown support
  • simpler middleware
  • authentication
  • background jobs
  • islands

Precisely this list shows that Topcoat still has a lot ahead of it.

But it simultaneously shows the ambition.

The goal is obviously not just another template framework.

Topcoat wants to become a complete web framework for Rust.

Conclusion: How far is web development in pure Rust in 2026?

Astonishingly far.

Topcoat is a good example of that.

We can today write a server-rendered web application, define components as asynchronous Rust functions, use Rust control flow directly in the markup, manage assets, integrate Tailwind, use sessions, and even formulate reactive client interactions in Rust.

Does the browser suddenly no longer need JavaScript for that?

No.

Topcoat translates supported reactive expressions into JavaScript.

Do we need WebAssembly?

Not for Topcoat's own reactivity model.

Do we necessarily need React, Vue, or Svelte?

Possibly not for many classic web applications either.

And that is precisely the interesting insight.

A few years ago, Rust on the web was mainly an interesting language for fast backends.

Today we discuss whether a complete web application including UI, routing, SSR, assets, sessions, and client reactivity can be developed within a Rust-centred stack.

Topcoat is still experimental and definitely not finished.

But perhaps that is precisely the most exciting point about this framework.

Topcoat does not show that JavaScript has disappeared.

It shows that Rust has come far enough that JavaScript no longer has to be the centre of every modern web application.

And a few years ago that would probably have sounded far less realistic.

Frequently asked questions about Topcoat

What is Topcoat in Rust?

Topcoat is an experimental full-stack web framework for Rust. It combines, among other things, server-side rendering, components, routing, assets, and client-side reactivity in a Rust-centred framework.

Does Topcoat require WebAssembly?

For Topcoat's own runtime, no WASM bundle is required. Supported reactive Rust expressions are instead translated into JavaScript for the browser.

Can Topcoat run Rust directly in the browser?

Not in the sense of a native Rust runtime in the browser. Topcoat can translate supported expressions from its runtime into JavaScript. Arbitrary Rust code cannot currently simply be run in the browser.

Is Topcoat production-ready already?

Topcoat currently describes itself as “early-stage and experimental” and warns of breaking changes. For long-lived production projects, this stage of development should be taken into account.

Can Topcoat use a database?

Yes. Topcoat components are server-side asynchronous Rust functions and can accordingly call server-side database logic. The concrete database library can, for example, be SQLx, Diesel, or SeaORM.

What are Topcoat shards?

Shards are components that can be re-rendered on the server when reactive arguments change. The new HTML is then inserted into the existing page.

What are Topcoat procedures?

Procedures are asynchronous server functions that can be called from the browser. They complement the server-centred model for interactions in which server logic actually has to be executed.

Is Topcoat an alternative to React?

For server-centred applications, Topcoat can take over parts of the tasks for which React or a similar frontend framework would otherwise be used. For strongly client-side SPAs, architecture and area of use differ considerably, however.

Does Topcoat support Tailwind CSS?

Yes. Topcoat documents integrated Tailwind support that can be included in the asset pipeline.

Can a web application be written completely in Rust?

Today, a very large part of a web application can be implemented in Rust. Topcoat goes one step further by allowing even certain client-side interactions to be written as Rust expressions. In the browser, these supported expressions are, however, executed as JavaScript.

Further reading

This article is based on the official documentation as of August 2026. Since Topcoat is explicitly experimental, the current documentation should always be checked before reproducing it.