Edge-Runtime, Content-Framework, Systems-Sprache – wie drei Technologien zusammenpassen, die man selten gemeinsam nennt
Wenn man lange genug Webprojekte baut, entwickelt man ein Gespür dafür, wo Reibung entsteht. Nicht die offensichtliche Reibung – Build bricht, Dependency fehlt. Sondern die strukturelle: Dev und Production verhalten sich anders. Das Backend braucht einen eigenen Server. Deployment ist ein eigener Workflow. Skalierung kostet Geld, bevor ein einziger Nutzer da ist.
Seit Cloudflare Astro übernommen hat und Rust-basierte Workers produktionsreif sind, gibt es einen Stack, der diese Reibung fast vollständig eliminiert. Nicht theoretisch – in der täglichen Arbeit.
Die drei Schichten
Astro: Das Frontend-Framework, das sich zurückhält
Astro ist kein Full-Stack-Framework, das alles können will. Es ist ein Content-Framework, das HTML ausliefert – schnell, mit minimaler Client-Side-Runtime, und mit der Möglichkeit, gezielt interaktive Inseln einzubauen (React, Svelte, Vue, was auch immer).
Seit Astro 6 läuft der Dev-Server auf Cloudflares workerd-Runtime. Das heißt: astro dev und Production sind identisch. Kein “works on my machine”, kein Node.js-Shim für Cloudflare-APIs. Was lokal läuft, läuft auf dem Edge.
Was Astro in diesem Stack übernimmt:
- SSG und SSR mit automatischer Entscheidung pro Route
- Content Collections für strukturierte Inhalte
- Server Islands für dynamische Fragmente in statischen Seiten
- API-Routes als leichtgewichtige Endpunkte
- Zugriff auf alle Cloudflare-Bindings über
Astro.locals.runtime
Cloudflare Workers: Die Runtime ohne Server
Workers sind keine Container. Sie laufen auf V8-Isolates – derselben Engine wie Chrome und Node.js, aber ohne das Betriebssystem drumherum. Das Ergebnis: Cold Starts unter 50ms, Ausführung auf über 300 Edge-Locations weltweit, Abrechnung pro Request statt pro Stunde.
Dazu kommen die integrierten Services, die man bei anderen Anbietern einzeln zusammenstecken muss:
| Service | Funktion | Vergleichbar mit |
|---|---|---|
| KV | Key-Value Store, global repliziert | Redis (für Lesezugriffe) |
| D1 | SQLite-Datenbank auf dem Edge | Managed SQLite / PlanetScale |
| R2 | Object Storage, S3-kompatibel | AWS S3 |
| Durable Objects | Stateful Serverless, Single-Threaded | Kein direktes Äquivalent |
| Queues | Asynchrone Nachrichtenverarbeitung | SQS / RabbitMQ |
| AI | Inference auf Cloudflares GPU-Netz | Replicate / Hugging Face Inference |
Das Entscheidende: All diese Services sind über Bindings erreichbar – kein HTTP-Call, kein SDK-Import, keine Latenz. Ein Binding ist ein In-Process-Zugriff auf dem selben Server.
Rust via WebAssembly: Das Backend ohne Docker
Hier wird es interessant. Rust kompiliert über wasm32-unknown-unknown zu WebAssembly und läuft als Worker auf Cloudflares Netz. Kein Container, kein Server, kein Deployment-Pipeline-Overhead.
Das workers-rs-Crate bietet Zugriff auf alle Cloudflare-Bindings – KV, D1, R2, Durable Objects, Queues, AI – direkt aus Rust. Über das http-Feature-Flag nutzt es Standard-http-Crate-Typen. Damit läuft axum als Router direkt auf Workers:
use axum::{routing::get, Router};
use worker::*;
async fn health() -> &'static str {
"ok"
}
fn router() -> Router {
Router::new().route("/health", get(health))
}
#[event(fetch)]
async fn fetch(
req: HttpRequest,
_env: Env,
_ctx: Context,
) -> Result<http::Response<axum::body::Body>> {
Ok(router().call(req).await?)
}
Das ist ein vollwertiger HTTP-Service – mit Routing, Middleware, JSON-Serialisierung via Serde – ohne Docker, ohne Server, ohne Port-Mapping.
Warum WebAssembly hier Docker ersetzt
Nicht pauschal. Nicht für alles. Aber für die typischen Backend-Services einer Webanwendung – API-Endpunkte, Datenverarbeitung, Auth-Logik – macht WASM auf Workers das Docker-Setup überflüssig.
Was wegfällt
- Kein Dockerfile. Kein Base-Image, keine Multi-Stage-Builds, keine Image-Registry.
- Kein Server-Management. Kein Provisioning, kein SSH, keine Uptime-Überwachung.
- Kein Port-Mapping. Kein Nginx-Reverse-Proxy, kein Docker-Compose-Netzwerk.
- Kein Cold-Start-Problem in der Praxis. Cloudflare parallelisiert den WASM-Start mit dem TLS-Handshake – der Nutzer merkt nichts.
- Kein Skalierungsproblem. Workers skalieren automatisch auf Tausende gleichzeitiger Requests. Keine Replica-Sets, kein Load Balancer.
Was bleibt
Rust auf Workers hat klare Grenzen:
- 128 MB RAM pro Invokation. Für die meisten API-Workloads irrelevant, für Bildverarbeitung oder große Datenmengen ein echtes Limit.
- Maximal 5 Minuten CPU-Zeit (Paid Plan). Batch-Jobs, die länger laufen, brauchen eine andere Lösung.
- Kein Dateisystem. Kein
std::fs, kein temporäres Verzeichnis. Daten müssen über KV, R2 oder D1 fließen. - Kein Threading. Workers sind Single-Threaded. Kein Tokio, kein async_std. Das
worker-Crate bringt seinen eigenen Executor mit. - Nicht jede Rust-Crate kompiliert. Alles, was auf
std::net,std::threadoderstd::fszugreift, funktioniert nicht aufwasm32-unknown-unknown. Das betrifft reqwest, diesel, sqlx und andere.
Wann Docker trotzdem richtig ist
- Datenbank-Server (PostgreSQL, MySQL)
- Batch-Jobs über 5 Minuten CPU-Zeit
- Workloads über 128 MB RAM
- Services, die nativen OS-Zugriff brauchen
- Legacy-Anwendungen, die nicht auf WASM portiert werden können
Seit Mitte 2025 bietet Cloudflare auch Cloudflare Containers (Public Beta) – Docker-Container, die von Workers orchestriert werden. Scale-to-Zero ist möglich, aber noch als Beta-Feature gekennzeichnet. Für die Fälle, die Workers allein nicht abdecken, bleibt man im selben Ökosystem.
Architektur: Wie die drei Schichten zusammenspielen
Service Bindings: Microservices ohne Netzwerk
Der Astro Worker ruft den Rust Worker nicht über HTTP auf. Stattdessen nutzt er ein Service Binding – ein In-Process-Call auf demselben Cloudflare-Server. Keine DNS-Auflösung, kein TLS-Handshake, keine Serialisierungskosten.
In der wrangler.toml des Astro Workers:
[[services]]
binding = "API"
service = "my-rust-worker"
Im Astro API-Route:
export async function GET({ locals }) {
const { env } = locals.runtime;
const response = await env.API.fetch(
new Request('https://internal/products', {
method: 'GET',
})
);
return new Response(await response.text(), {
headers: { 'Content-Type': 'application/json' },
});
}
Der Rust Worker braucht keine öffentliche URL. Er ist nur über das Binding erreichbar – ein internes, typsicheres Interface zwischen Frontend und Backend.
Unabhängige Deployments
Astro und Rust Worker werden getrennt deployt. Das Frontend kann ein neues Design ausrollen, ohne das Backend anzufassen. Das Backend kann eine neue API-Version deployen, ohne den Build des Frontends auszulösen. Beide leben im selben Cloudflare-Account, nutzen dieselben Bindings, sind aber eigenständige Einheiten.
Performance: Was die Kombination bringt
Kein Origin-Server
Bei einem klassischen Setup geht jeder dynamische Request vom Edge zum Origin und zurück. Bei Cloudflare Workers gibt es keinen Origin. Astro rendert auf dem Edge. Der Rust Worker läuft auf dem Edge. D1 und KV liegen auf dem Edge. Die gesamte Kette – vom Request bis zur Antwort – findet auf dem nächstgelegenen Cloudflare-Server statt.
Cold Starts vs. Docker
| Metrik | Docker (klassisch) | Rust Worker |
|---|---|---|
| Cold Start | 1-30 Sekunden | unter 50ms |
| Standby-Kosten | Ja (Server läuft immer) | Nein (Pay per Request) |
| Skalierung | Manuell oder Auto-Scaling mit Delay | Automatisch, sofort |
| Globale Verfügbarkeit | 1 Region (oder Multi-Region Setup) | 300+ Locations |
Wann Rust schneller ist als JS/TS
Nicht immer. Für I/O-lastige Aufgaben – KV-Lookups, D1-Queries, externe API-Calls – ist JavaScript auf Workers schneller, weil kein WASM-Bridge-Overhead entsteht.
Rust lohnt sich, wenn CPU-intensive Arbeit anfällt:
- JSON-Parsing großer Payloads
- Daten-Transformation und Validierung
- Kryptographie und Hashing
- Bildverarbeitung (Cloudflare hat ihr Images-Produkt in Rust auf Workers gebaut)
- Encoding/Decoding (Base64, Protobuf, CSV)
Für reine Proxy- oder Routing-Logik ist TypeScript auf Workers die pragmatischere Wahl.
Kosten: Was das Setup kostet
Cloudflare Workers Paid Plan
| Posten | Inklusiv | Überschreitung |
|---|---|---|
| Grundgebühr | 5 USD/Monat | - |
| Requests | 10 Mio/Monat | 0,30 USD pro Mio |
| CPU-Zeit | 30 Mio ms/Monat | 0,02 USD pro Mio ms |
| KV Reads | 10 Mio/Monat | 0,50 USD pro Mio |
| D1 Reads | 25 Mio Zeilen/Monat | 0,001 USD pro Mio |
| R2 Storage | 10 GB | 0,015 USD pro GB |
| Egress | Kostenlos | Kostenlos |
Vergleich mit klassischem Setup
Für eine typische Content-Website mit API-Backend (500.000 Requests/Monat):
| Setup | Monatliche Kosten |
|---|---|
| Cloudflare Workers (Astro + Rust) | ca. 5 USD |
| Hetzner VPS + Docker + Nginx | ca. 5-10 EUR |
| Vercel Pro + separates Backend | ca. 20+ USD |
| AWS (CloudFront + Lambda + RDS) | ca. 30-100 USD |
Der Kostenvorteil von Workers kommt nicht aus günstigeren Preisen pro Einheit, sondern aus drei Faktoren: kein Egress-Traffic, kein Standby-Verbrauch und keine Infrastruktur-Verwaltung.
Bei hohem Traffic (über 50 Mio Requests) oder CPU-intensiven Workloads dreht sich das Verhältnis um – dann kann ein gut ausgelasteter VPS günstiger sein.
Der Build-Workflow
Astro
# Installation
npx astro add cloudflare
# Development (läuft auf workerd)
astro dev
# Build + Deploy
astro build && wrangler deploy
Rust Worker
# wrangler.toml
name = "my-api"
main = "build/worker/shim.mjs"
compatibility_date = "2026-01-01"
[build]
command = "cargo install -q worker-build && worker-build --release"
# Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
worker = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
[profile.release]
opt-level = "s"
lto = true
codegen-units = 1
# Development
wrangler dev
# Deploy
wrangler deploy
Beide Workflows sind wrangler-basiert. Kein separater CI/CD-Prozess nötig – obwohl man natürlich einen haben kann.
Binary-Größe optimieren
Rust-WASM-Binaries können groß werden. Über 1 MB komprimiert verschlechtert sich die Cold-Start-Performance spürbar. Die wichtigsten Stellschrauben:
opt-level = "s"statt"3"– optimiert auf Größe statt Geschwindigkeitlto = true– Link-Time-Optimization entfernt ungenutzten Codecodegen-units = 1– bessere Optimierung, längerer Build- Abhängigkeiten minimieren – jede Crate, die mitkompiliert wird, vergrößert das Binary
wasm-optläuft automatisch überworker-build
Das Bundle-Limit liegt bei 10 MB komprimiert (Paid Plan). In der Praxis sollte man unter 1 MB bleiben.
Datenschutz und Datenlokalisierung
Für deutsche und europäische Projekte ist die DSGVO-Frage nicht optional. Cloudflare hat hier in den letzten Jahren nachgelegt:
- Workers laufen in EU-Rechenzentren. Cloudflare betreibt Server unter anderem in Frankfurt, Amsterdam, Paris und Dublin. Über die Data Localization Suite lässt sich erzwingen, dass Daten nur in EU-Regionen verarbeitet werden.
- D1, KV und R2 sind standardmäßig global verteilt. Für DSGVO-sensible Daten muss man die Datenlokalisierung explizit konfigurieren – bei R2 über die Region-Wahl beim Erstellen des Buckets, bei D1 über den Location Hint.
- Kein US-Cloud-Act-Problem im klassischen Sinn. Cloudflare ist ein US-Unternehmen, aber die Verarbeitung personenbezogener Daten kann über die Lokalisierungsoptionen in der EU gehalten werden. Das DPA (Data Processing Agreement) von Cloudflare deckt die EU-Standardvertragsklauseln ab.
In der Praxis: Für Content-Websites ohne personenbezogene Daten (kein Login, keine Formulare mit PII) ist das unproblematisch. Sobald Nutzerdaten ins Spiel kommen – Kontaktformulare, Kundenkonten, Analytics – muss man die Lokalisierung aktiv konfigurieren. Das ist kein Showstopper, aber es ist kein Automatismus.
Lokale Entwicklung: Was wirklich offline läuft
Astro 6 mit dem Cloudflare-Adapter nutzt im Dev-Modus workerd lokal – die gleiche Runtime wie in Production. Das funktioniert ohne Cloudflare-Account für reine Astro-Features, Content Collections und SSR.
Für den Rust Worker sieht es anders aus: wrangler dev startet eine lokale Instanz über Miniflare, das die Workers-Umgebung simuliert. KV, D1 und R2 laufen dabei als lokale SQLite- bzw. Datei-basierte Backends – kein Cloudflare-Account nötig für die Entwicklung.
# Astro Dev-Server (workerd-basiert, lokal)
astro dev
# Rust Worker Dev-Server (Miniflare-basiert, lokal)
wrangler dev
# Beide zusammen: Astro ruft Rust Worker via Service Binding auf
# → Aktuell noch getrennte Prozesse, kein Hot-Reload über die Grenze
Die Einschränkung: Service Bindings zwischen Astro und Rust Worker funktionieren lokal nur, wenn beide Prozesse laufen und korrekt verlinkt sind. Das Setup ist etwas umständlicher als ein einzelner docker-compose up, dafür ist jeder Teil unabhängig testbar.
Was diese Kombination nicht kann
Kein Stack ist universell. Cloudflare + Astro + Rust passt nicht für:
- SPAs mit komplexem Client-State. Astro ist ein Content-Framework. Für eine Figma-artige Anwendung nimmt man React oder Svelte als Haupt-Framework.
- Schwere Datenbank-Workloads. D1 ist SQLite auf dem Edge – für einfache Queries hervorragend, für komplexe Joins oder Volltextsuche über Millionen Zeilen nicht gedacht. Wer PostgreSQL braucht, braucht einen echten Datenbankserver.
- Langläufer. Batch-Verarbeitung, Video-Encoding, ML-Training – alles über 5 Minuten CPU-Zeit gehört nicht auf Workers.
- Teams ohne Rust-Erfahrung. Der Rust-Layer ist optional. Wer TypeScript bevorzugt, baut das Backend als normalen Worker in TS. Die Astro-Cloudflare-Kombination funktioniert auch ohne Rust.
Warum nicht Next.js + Vercel?
Die Frage kommt unweigerlich. Kurz:
- Vercel ist teurer. Egress kostet, Pro-Plan kostet, Bandwidth-Limits existieren.
- Next.js ist schwerer. Mehr Client-Side JavaScript, längere Ladezeiten für Content-Sites.
- Vendor Lock-in ist stärker. Next.js auf Nicht-Vercel-Plattformen zu deployen erfordert Workarounds. Astro auf Nicht-Cloudflare-Plattformen funktioniert out of the box.
- Runtime-Overhead. Next.js braucht eine Node.js-Runtime oder Edge Runtime mit Einschränkungen. Astro auf Cloudflare läuft nativ auf V8-Isolates.
Für komplexe React-Anwendungen mit viel Interaktion ist Next.js nach wie vor die bessere Wahl. Für Content-getriebene Websites, Marketing-Seiten, Blogs, Dokumentation und hybride Sites mit punktueller Interaktion ist Astro auf Cloudflare performanter, günstiger und einfacher zu betreiben.
Migration: Wie man aus einem bestehenden Setup kommt
Wer aktuell auf Next.js + Vercel, Netlify oder einem VPS mit Docker sitzt, kann schrittweise umsteigen.
Von Next.js zu Astro
Astro kann React-Komponenten direkt einbinden – als Islands mit client:load oder client:visible. Das bedeutet: Man muss nicht alle Komponenten neu schreiben. Seiten lassen sich Stück für Stück migrieren, während bestehende React-Logik als interaktive Inseln weiterlebt.
Die größte Umstellung ist das Routing: Next.js nutzt Dateibasiertes App-Router-Routing mit Layouts und Loading-States. Astro hat ebenfalls dateibasiertes Routing, aber ohne das verschachtelte Layout-System. Für Content-Sites ist das einfacher, für komplexe App-Flows muss man umdenken.
Von S3 zu R2
R2 ist S3-kompatibel. In vielen Fällen reicht es, die Endpoint-URL und die Credentials zu tauschen. AWS SDK und s3cmd funktionieren mit R2 – die Migration ist oft ein Konfigurationswechsel, kein Code-Umbau.
Von Docker-Backend zu Rust Worker
Das ist der aufwändigste Schritt und nicht immer nötig. Wer ein Express- oder Fastify-Backend hat, kann es als TypeScript Worker deployen – ohne Rust. Die Workers-Plattform unterstützt JS/TS als First-Class-Citizen. Rust lohnt sich erst, wenn man CPU-intensive Logik hat oder die Typsicherheit und Performance-Garantien von Rust bewusst nutzen will.
Der pragmatische Pfad: Erst Astro auf Cloudflare deployen (Frontend). Dann schrittweise API-Endpunkte als Workers aufbauen (TS oder Rust). Zuletzt den alten Server abschalten.
Einordnung
Cloudflare + Astro + Rust ist kein Hype-Stack. Es ist die konsequente Kombination aus drei Technologien, die jeweils in ihrer Kategorie das Beste liefern: Astro für Content-Sites, Cloudflare für Edge-Runtime, Rust für performante Backend-Logik.
Was das Dreieck zusammenhält, ist nicht ein einzelnes Feature, sondern die Abwesenheit von Reibung. Dev und Production sind identisch. Frontend und Backend kommunizieren ohne Netzwerk. Deployment ist ein einzelner Befehl. Skalierung passiert automatisch. Kosten entstehen nur bei Nutzung.
Kein Docker. Kein Nginx. Kein Load Balancer. Kein Origin-Server. Für Content-getriebene Webprojekte mit API-Backend ist das aktuell die schlankeste Architektur, die ich kenne.