Cloudflare Workers SSR: Ein vollständiger Leitfaden für Full-Stack

Erstellen und betreiben Sie Ihre Full-Stack-Anwendung auf Cloudflare Workers mit Streaming SSR, D1, R2, Queues sowie Workflows aus realen Deployments.

Huifer
Huifer
20. Juli 202613 min read
Auch verfügbar auf:English · 中文

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich habe zwischen 2023 und 2026 12+ Produktions-Apps auf Cloudflare Workers + TanStack Start online gebracht. Die in diesem Leitfaden beschriebenen Muster sind diejenigen, die tatsächlich in der Produktion eingesetzt wurden – nicht die, die in Demos am besten aussahen. Die hier beschriebene Architektur betreibt mein eigenes SaaS für rund 14 $/Monat mit Kaltstarts von unter 50 ms. Wo Cloudflare Workers noch Schwächen aufweist, werde ich diese benennen.

Verifizierte Quellen: Cloudflare Workers Docs · D1 Docs · TanStack Start Docs · TanStack Ship GitHub Zuletzt aktualisiert: 2026-07-20 · Changelog


TL;DR: Cloudflare Workers führt JavaScript an der Edge in V8-Isolates aus – nicht in Containern. In Kombination mit dem Streaming SSR von TanStack Start, D1 für die Datenbank, R2 für Dateien sowie Queues + Workflows für Hintergrundarbeiten erhalten Sie eine Full-Stack-SaaS-Architektur, die schnell, kostengünstig und global verteilt ist. Dieser Leitfaden führt Sie durch den gesamten Stack: Setup, Streaming SSR, D1, R2, Deployment, Monitoring und Kosten. Reale Zahlen eines Produktions-Deployments mit 12 Modulen sind inklusive.


Warum Cloudflare Workers für SSR?

Drei Gründe, die zusammen diese Architektur rechtfertigen.

1. Kaltstart unter 50 ms

Cloudflare Workers läuft in V8-Isolates, nicht in Containern. Es gibt kein Hochfahren von Containern, keinen Node.js-Bootstrap, keinen Aufwand für Modulauflösungen. Die erste Anfrage nach dem Deployment trifft auf die Laufzeitumgebung und wird in wenigen zehn Millisekunden ausgeführt. Für SSR, bei dem TTFB direkt der vom Nutzer wahrgenommenen Latenz entspricht, ist dies der Unterschied zwischen „schnell“ und „sofort reaktionsfähig“.

2. Das Kostenprofil ist drastisch niedriger

Ein bescheidenes SaaS auf Cloudflare Workers kostet unter Produktionslast 5–20 $/Monat. Dieselbe App auf einem Host-basierenden Container kostet 50–200 $/Monat. Das Abrechnungsmodell erfolgt pro Anfrage und nicht nach inaktivem Container, sodass die Kosten mit der tatsächlichen Nutzung und nicht mit der bereitgestellten Kapazität skalieren.

3. Die Plattform ist kohärent

Cloudflare Workers, D1 (SQLite an der Edge), R2 (S3-kompatibler Speicher), Queues (Message Queue), Workflows (robuste Ausführung), KV (Key-Value Store), Durable Objects (zustandsbehaftete Koordination) – sie alle befinden sich im selben Dashboard, haben dieselbe Abrechnung und dieselbe Deployment-Geschichte. Es gibt kein Wildwuchs wie „Workers App, RDS Datenbank, S3 Bucket, SQS Queue“. Alles wird in der wrangler.toml konfiguriert.

Der Kompromiss: Cloudflare Workers hat ein Speicherlimit von 128 MB pro Isolate, CPU-Zeitlimits im kostenlosen Plan und einige Node.js APIs sind nicht verfügbar. Für einen SaaS-Workload sind dies alles keine Ausschlusskriterien – aber Sie sollten sie von Anfang an kennen. Ich werde die problematischen Stellen benennen, an denen sie auftreten.

Wann Sie Cloudflare Workers NICHT verwenden sollten

Ehrlichkeit ist hier wichtig. Cloudflare Workers ist nicht für jeden Workload die richtige Wahl.

CPU-lastige synchrone Arbeiten

Das CPU-Zeitlimit von Cloudflare Workers beträgt im kostenpflichtigen Plan 30 Sekunden, aber der praktische Sweet Spot liegt bei unter 50 ms. Wenn Ihre Route CPU-lastige synchrone Arbeiten (Bildverarbeitung, Videotranskodierung, komplexe mathematische Simulationen) ausführt, ist Cloudflare Workers die falsche Laufzeitumgebung. Verwenden Sie für solche Workloads einen Container-basierten Host.

Apps, die auf langlebige Verbindungen angewiesen sind

Cloudflare Workers kann eine einzelne Verbindung nicht über Stunden offen halten. WebSocket-lastige Anwendungen – Chat-Apps, Echtzeit-Kollaborationstools, Live-Streaming – benötigen Durable Objects oder einen anderen Host. Diese Einschränkung ist grundlegend für das V8-Isolate-Modell.

Apps, die eine traditionelle relationale Datenbank benötigen

D1 ist SQLite, und der Schreibdurchsatz von SQLite ist begrenzt. Wenn Ihre App dauerhaft tausende Schreibvorgänge pro Sekunde benötigt, ist D1 die falsche Wahl. Richten Sie für diese Workloads eine Queue auf eine externe Postgres-Datenbank (Neon, Supabase, RDS) und nehmen Sie die architektonische Komplexität in Kauf.

Apps mit großer, bestehender Infrastruktur

Wenn Sie bereits über RDS, S3, SQS, ECS und ein Jahr an IaC verfügen, ist die Migration zu Cloudflare Workers ein Rewrite und kein Refactoring. Der Wert von Cloudflare Workers ist bei neuen Greenfield-Projekten und Apps, die bereit sind, die nativen Workers-Bausteine anzunehmen, am höchsten.

Einrichten eines TanStack Start Projekts auf Cloudflare Workers

Der schnellste Weg im Jahr 2026 führt über das TanStack Start CLI:

bash
# Projekt erstellen
npm create @tanstack/start@latest my-saas
cd my-saas

# Cloudflare Workers Adapter hinzufügen
npm install @tanstack/start-cloudflare-workers

# wrangler.toml-Gerüst generieren
npx wrangler init

Das CLI generiert eine wrangler.toml wie diese:

toml
name = "my-saas"
main = "./dist/server/index.js"
compatibility_date = "2026-07-01"
compatibility_flags = ["nodejs_compat"]

[[d1_databases]]
binding = "DB"
database_name = "my-saas-prod"
database_id = "your-database-id"

[[r2_buckets]]
binding = "STORAGE"
bucket_name = "my-saas-uploads"

[[queues.producers]]
binding = "BILLING_QUEUE"
queue = "billing-events"

[[kv_namespaces]]
binding = "CACHE"
id = "your-kv-id"

[vars]
APP_ENV = "production"

Jeder [[bindings]]-Block gibt Ihrem Worker ein typisiertes Binding – env.DB, env.STORAGE usw. –, das in Server Functions zugänglich ist. Das nodejs_compat-Flag aktiviert Node.js-API-Polyfills für Bibliotheken, die diese benötigen.

Für einen vollständigen Leitfaden zum Deployment mit TanStack Start lesen Sie die TanStack Ship Features-Seite; für Routing-Muster lesen Sie den Leitfaden zu Streaming SSR.

Streaming SSR: Wie es funktioniert

Streaming SSR ist die Technik, bei der der Server HTML an den Browser sendet, sobald jedes Teil fertig ist, anstatt darauf zu warten, dass die vollständige Seite gerendert wird, bevor irgendwelche Bytes gesendet werden.

In React 19 ist dies über die <Suspense>-Boundary implementiert. Jede Suspense-Boundary sendet ihren Inhalt an den Browser, sobald sie aufgelöst wird:

tsx
// app/dashboard/page.tsx
import { Suspense } from "react";
import { LoadingSkeleton } from "~/components/loading-skeleton";

export default function DashboardPage() {
  return (
    <main>
      <h1>Dashboard</h1>

      {/* Wird sofort gesendet */}
      <Suspense fallback={<LoadingSkeleton />}>
        <RecentOrders /> {/* Async Server Component — streamt, wenn bereit */}
      </Suspense>

      {/* Wird sofort gesendet */}
      <Suspense fallback={<LoadingSkeleton />}>
        <MonthlyRevenue /> {/* Async Server Component — streamt, wenn bereit */}
      </Suspense>
    </main>
  );
}

Der Browser erhält sofort das Grundgerüst der Seite und empfängt dann die Abschnitte für aktuelle Bestellungen und monatliche Einnahmen, sobald sich diese auflösen. TTFB sinkt von „Zeit zum Rendern der gesamten Seite“ auf „Zeit zum Rendern des Grundgerüsts der Seite“.

Die Auswirkung auf die Leistung: In der Produktion senkt Streaming SSR den Median der TTFB auf einem typischen SaaS-Dashboard von ~180ms auf ~40ms. Das ist der Unterschied zwischen „fühlt sich schnell an“ und „fühlt sich sofort an“.

Wo Streaming am meisten hilft

Streaming hilft am meisten auf Seiten mit mehreren asynchronen Datenquellen. Eine Login-Seite, die Benutzerinformationen, den Abrechnungsstatus und Benachrichtigungen lädt, streamt alle drei parallel anstatt nacheinander. Eine Produktdetailseite, die Produktinformationen, Lagerbestände und Bewertungen lädt, streamt ebenfalls alle drei parallel.

Am wenigsten hilft Streaming bei Seiten mit nur einer einzigen Datenquelle. Es gibt nichts zu streamen, wenn nur auf ein einzelnes Datenelement gewartet werden muss.

Muster, die skalieren vs. Muster, die nicht skalieren

Zwei Muster skalieren gut auf Cloudflare Workers; zwei nicht.

Skaliert gut: viele kleine, unabhängige Abfragen, die parallel über Suspense aufgelöst werden. Das Framework fächert sich auf, Isolates lösen sich gleichzeitig auf, und der Nutzer sieht eine schnelle TTFB, während sich der Inhalt füllt.

Skaliert gut: synchrone Einzel-Abfrage-Routen, die in 10–50ms abgeschlossen sind. Die Anfrage passt in ein einzelnes CPU-Zeitbudget, keine Wiederholungsversuche erforderlich, keine asynchrone Koordination.

Skaliert nicht gut: eine einzelne Route, die 10 aufeinanderfolgende Abfragen absetzt und auf jede wartet. Die Gesamtzeit ist die Summe; der Nutzer wartet.

Skaliert nicht gut: eine Route, die einen großen Datensatz (Megabytes) lädt und ihn vor der Antwort im Speicher serialisiert. Das Speicherlimit von 128 MB und das CPU-Zeitbudget werden Sie stoppen. Paginieren Sie stattdessen.

Die Regel: Entwerfen Sie Routen so, dass sie begrenzte Arbeit verrichten, parallelisieren Sie über Suspense-Boundaries hinweg und streamen Sie so viel wie möglich.

D1: Die Datenbank an der Edge

D1 ist die verteilte SQLite-Datenbank von Cloudflare. Lesevorgänge replizieren sich in jede Region; Schreibvorgänge gehen an eine primäre Region und replizieren sich dort. Für SaaS-Workloads unter ein paar hundert Schreibvorgängen pro Sekunde und Region ist D1 die günstigste und schnellste verfügbare Datenbanklösung.

Schema und Migrationen

Das Standardmuster ist die Verwendung des Drizzle ORM mit einem Migrations-Workflow:

ts
// db/schema.ts
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  email: text("email").notNull().unique(),
  createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
});

export const subscriptions = sqliteTable("subscriptions", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  userId: integer("user_id").references(() => users.id).notNull(),
  status: text("status").notNull(),
  stripeCustomerId: text("stripe_customer_id").notNull(),
});
bash
# Migration generieren
npx drizzle-kit generate

# Lokal anwenden
npx wrangler d1 migrations apply my-saas-prod --local

# In der Produktion anwenden
npx wrangler d1 migrations apply my-saas-prod --remote

Die Write-Lock-Einschränkung

Der Write-Lock von D1 gilt global pro Datenbank. Bei über ~60 req/s an Schreibvorgängen machen sich Konflikte bemerkbar. Bei über ~200 req/s dominieren diese Konflikte. Die Lösung besteht darin, Schreibvorgänge durch eine Pipeline aus Cloudflare Queue + Workflow zu schleusen – ein Muster, das im D1 Write-Lock Postmortem dokumentiert ist. Für SaaS-Workloads mit geringerem Traffic sind synchrone Schreibvorgänge völlig in Ordnung.

Für tiefergehende D1-Muster lesen Sie den D1-Produktionsleitfaden und den Artikel über D1 Abfrage-Optimierungstechniken.

R2: Dateispeicher

R2 ist ein S3-kompatibler Objektspeicher ohne Egress-Gebühren. Das Detail des Null-Egress ist wichtiger, als es klingt: Ein SaaS, das nutzerhochgeladene Bilder bei jedem Seitenaufruf ausliefert, hätte eine spürbare AWS-Rechnung zu tragen; derselbe Workload auf R2 ist für den Speicher- und Auslieferungsweg praktisch kostenlos.

Das Muster

ts
// Upload-Handler
export const uploadAvatar = createServerFn().handler(async ({ data }) => {
  const key = `avatars/${crypto.randomUUID()}`;
  await env.STORAGE.put(key, data.file, {
    httpMetadata: { contentType: data.file.type },
  });
  return { key, url: `https://cdn.example.com/${key}` };
});

// Auslieferung über eine benutzerdefinierte Domain, die an den R2-Bucket gebunden ist
// (wird im Cloudflare-Dashboard konfiguriert, nicht im Code)

Verbinden Sie Ihre CDN-URL mit einer benutzerdefinierten Domain für Ihren R2-Bucket. Die Einrichtung erfolgt einmalig im Cloudflare-Dashboard; der Code muss niemals signierte URLs konstruieren, da die benutzerdefinierte Domain den Bucket öffentlich lesbar macht.

Queues + Workflows: Hintergrundarbeiten

Zwei Grundbausteine, die zusammen für fast jede Hintergrundaufgabe eingesetzt werden.

Queues

Cloudflare Queues ist eine Message Queue mit „at-least-once“-Zustellung (mindestens einmal). Verwenden Sie es für: Webhook-Verteilung, E-Mail-Trigger, gebündelte Schreibvorgänge und auftretende Jobs mit Wiederholungsmöglichkeit.

ts
// Produzent
await env.BILLING_QUEUE.send({
  type: "subscription.renewed",
  payload: { userId: 123, amount: 4900 },
});

// Konsument
export default {
  async queue(batch: MessageBatch<unknown>, env: Env) {
    for (const msg of batch.messages) {
      await processBillingEvent(msg.body, env);
      msg.ack();
    }
  },
};

Workflows

Cloudflare Workflows bieten eine stabile Ausführung mit Wiederholungsversuchen, Verzögerungen und schrittbasierter Zusammensetzung. Verwenden Sie es für: mehrstufige Onboarding-Abläufe, geplante Jobs und Logik für Wiederholungsversuche mit Backoff.

ts
// Workflow-Definition
export class OnboardingWorkflow implements Workflow {
  async run(event: Payload, step: WorkflowStep) {
    await step.do("create-account", async () => createAccount(event));
    await step.sleep("wait-24h", "24h");
    await step.do("send-day-1-email", async () => sendEmail(event));
  }
}

Die Kombination – Queue für „Fire-and-Forget“-Ereignisse, Workflow für mehrstufige, stabile Ausführungen – deckt 95 % der Muster für Hintergrundarbeiten in einem SaaS ab. Für die restlichen 5 % übernehmen Durable Objects die zustandsbehaftete Koordination (Chat-Räume, Multiplayer-Spiele, Rate Limiter).

Deployment

bash
# Produktions-Deployment
npx wrangler deploy

# Mit Secrets
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put RESEND_API_KEY

# Tail-Logs anzeigen
wrangler tail --format=pretty

# D1 Einblicke
wrangler d1 insights --database=my-saas-prod

Das erste Deployment dauert etwa 30 Sekunden; nachfolgende Deployments beanspruchen weniger als 10 Sekunden. Das Dashboard unter dash.cloudflare.com zeigt Anfragen, Fehler, CPU-Zeit und routenbasierte Analysen an. Für weitreichende Überwachungsmöglichkeiten leiten Sie wrangler tail über Logpush an Datadog oder Grafana weiter.

Monitoring und Logging

Drei Dinge, die ich bei jeder Cloudflare Workers-App überwache:

  1. CPU-Zeit p99 pro Route. Cloudflare Workers berechnet CPU-Zeit; lang laufende Routen kosten mehr. Wenn p99 über 50ms klettert, gehen Sie der Sache auf den Grund.
  2. Fehlerrate pro Route. Das Cloudflare-Dashboard zeigt dies an; Warnungen gehen über einen Webhook an Discord.
  3. D1 write_lock_wait_ms. Dies ist die Frühwarnung für das Ausmaß des Write-Lock-Vorfalls.
bash
# Einfachen Cron-Alarm einrichten
watch -n 60 'wrangler d1 insights --database=my-saas-prod | grep write_lock'

Oder verwenden Sie Logpush, um Streams an Datadog zu senden und dort Warnmeldungen zu erstellen. Welches genaue Tooling verwendet wird, spielt keine so große Rolle wie die Disziplin, diese drei Metriken im Auge zu behalten.

Kostenanalyse

Zahlen aus meinem Produktions-Deployment (TanStack Ship selbst):

  • Cloudflare Workers: ~5 $/Monat bei ~5 Millionen Anfragen/Monat
  • D1: ~4 $/Monat bei 200.000 Lesevorgängen + 50.000 Schreibvorgängen
  • R2: ~1 $/Monat bei 10 GB Speicherplatz + 50 GB Egress
  • Queues: ~1 $/Monat bei 1 Mio. Nachrichten
  • Workflows: ~1 $/Monat bei 50.000 Schrittausführungen
  • KV: ~2 $/Monat bei 100.000 Lesevorgängen

Gesamt: rund 14 $/Monat für ein SaaS, das 3.200 Kunden mit vollständigem SSR, Datenbank, Dateispeicher und Hintergrundarbeiten bedient. Die entsprechende Architektur auf AWS würde schätzungsweise 80–150 $/Monat kosten; auf Vercel + einer verwalteten Datenbank 60–100 $/Monat.

Die Limits, die Sie kennen sollten

Cloudflare Workers hat Einschränkungen. Machen Sie sich diese im Vorfeld bewusst.

128 MB Speicher pro Isolate

Für die meisten SaaS-Routen ist dies komfortabel. Bei Routen, die große Datensätze laden, paginieren oder streamen Sie.

CPU-Zeitlimits

Der kostenlose Plan beschränkt die CPU-Zeit auf 10ms pro Anfrage (mit einigen Ausnahmen). Der kostenpflichtige Plan beschränkt sie auf 50ms im Standard-Tarif und auf 30 Sekunden im Unbound-Tarif (sofern Sie diesen nutzen). Die meisten SSR-Routen passen in das Zeitfenster von 50ms; Routen, die schwere Datenbankarbeit oder Bildverarbeitung durchführen, möglicherweise nicht.

Keine langlebigen Verbindungen

Cloudflare Workers kann WebSocket-Verbindungen nicht stundenlang aufrechterhalten. Durable Objects bewältigen diesen Fall. Wenn Sie Echtzeit benötigen, planen Sie mit DO.

nodejs_compat deckt die meisten, aber nicht alle Node APIs ab

Einige npm-Pakete setzen ein Node-spezifisches Verhalten voraus, das Cloudflare Workers nicht bietet. Das nodejs_compat-Flag deckt die meisten Polyfills ab; für den Rest müssen Sie möglicherweise eine alternative Bibliothek finden. Dies ist im Jahr 2026 selten, kommt aber vor.

Kein Dateisystem

fs ist nicht verfügbar. Alle Daten laufen über D1, R2, KV oder DO. Dies ist nur selten eine Einschränkung für SaaS, aber wenn Sie nach fs.readFile greifen, müssen Sie umdenken.

Alles zusammenfügen

Eine Produktions-SaaS-Architektur auf Cloudflare Workers sieht wie folgt aus:

  • TanStack Start für SSR, Routing und typsicheres Laden von Daten
  • Cloudflare Workers als Laufzeitumgebung
  • D1 für die Datenbank (SQLite an der Edge)
  • R2 für den Dateispeicher (CDN ohne Egress-Gebühren)
  • Queues zur Ereignisverteilung und für asynchrone Schreibvorgänge
  • Workflows für stabile, mehrstufige Hintergrundarbeiten
  • Durable Objects, wenn Sie eine zustandsbehaftete Koordination benötigen (Rate Limits, Echtzeit)
  • KV für Caches und Feature-Flags
  • Stripe + Resend für Zahlungen und E-Mail (Cloudflare Workers führt externe HTTP-Aufrufe problemlos durch)

Dieser Stack führt TanStack Ship in der Produktion für 14 $/Monat mit Kaltstarts von unter 50 ms und einer Verfügbarkeit von 99,95 % aus. Die in diesem Leitfaden enthaltenen Muster sind dieselben, die ich jedem empfehlen würde, der im Jahr 2026 ein SaaS auf Cloudflare Workers entwickelt.

Für weiterführende Deep Dives lesen Sie Streaming SSR erklärt, das SaaS Tech Stack 2026 Entscheidungs-Framework und die TanStack Ship Funktionsübersicht.


Legen Sie los mit TanStack Ship – einem SaaS-Startpaket mit 14 Modulen auf Cloudflare Workers. Kostenloses Startpaket klonen → · Preise ansehen