Cloudflare Workers Mobile Backend: $5/Monat bei 1M Requests

Wir haben 1M mobile API-Requests/Tag auf Cloudflare Workers für $5/Monat betrieben. Reale Architektur: D1, R2, KV, Durable Objects, 50ms p99 Cold Start, kein Node-Server.

Huifer
Huifer
8. Mai 202612 min read
Auch verfügbar auf:English · 中文

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich habe ein Mobile-App-Backend (iOS + Android) von Oktober 2025 bis April 2026 auf Cloudflare Workers betrieben. Spitzenauslastung: 1,1M Requests/Tag. Die Architektur, die Kosten von $5/Monat und der 50ms-p99-Cold-Start-Wert stammen aus diesem Produktivsystem, nicht aus einem Benchmark-Labor. Das 30-Sekunden-CPU-Limit und die iOS-NSURLSession-Eigenheiten sind ebenfalls aus diesem Build dokumentiert.

Verifizierte Quellen: Cloudflare Workers Documentation · Cloudflare D1 Documentation · Cloudflare R2 Documentation · Cloudflare KV Documentation · Cloudflare Durable Objects · TanStack Start Server Functions · Stripe Mobile Backend Patterns · TanStack Ship GitHub

Zuletzt aktualisiert: 08.05.2026 · Changelog

TL;DR: Ein Mobile-App-Backend auf Cloudflare Workers ist real, produktionsreif und günstig. Die Referenzarchitektur nutzt vier Bindings – D1 für relationale Daten, R2 für Medien, KV für Cache und Konfiguration, Durable Objects für Echtzeit – verdrahtet in je einem Worker pro Routengruppe. 50ms p99 Cold Start. $5/Monat Workers Paid bei 30M Requests/Monat. $0,08/Monat R2 bei 10GB. Im Folgenden: die Architektur, die Benchmark-Methodik, der Produktivcode, die Kostenrechnung und die vier Fälle, in denen Sie dennoch eine andere Stack-Wahl treffen sollten.


Warum Mobile Backends auf CF Workers anders sind

Cloudflare Workers werden oft als „serverlose Funktionen am Edge" beworben. Diese Darstellung unterschätzt, was sie tatsächlich sind. Ein Worker ist ein V8-Isolate (siehe die Workers-Runtime-Dokumentation), das JavaScript oder TypeScript in wenigen Millisekunden in über 330 Städten ausführt, mit geteilten Bindings an vier Speicherprimitive: D1 (SQLite am Edge), R2 (S3-kompatibler Objektspeicher ohne Ausgangsgebühren), KV (eventuell konsistenter Key-Value-Speicher) und Durable Objects (single-threaded koordinierter Zustand). Die Kombination ist es, was Mobile Backends auf Workers gegenüber AWS Lambda oder Google Cloud Functions wirklich anders macht – die Speicherprimitive sind First-Class, keine nachträglichen Ergänzungen.

Für ein Mobile-App-Backend macht dieser Unterschied in drei Punkten einen echten Unterschied:

  1. Der Mobile Client verbindet sich automatisch mit dem nächstgelegenen Rechenzentrum. Keine regionale Konfiguration, keine CloudFront-Distributionen, keine Latenz-Routing-Regeln. Ein Nutzer in Berlin trifft den Frankfurter Worker; ein Nutzer in São Paulo trifft den Worker in São Paulo. p50 TTFB sinkt von 180ms (Single-Region Node) auf 35ms.
  2. Die Speicher-Bindings sind collocated. D1-Lese- und Schreibvorgänge finden im selben V8-Isolate wie der API-Handler statt. Kein Netzwerk-Hop zu einem Datenbank-Cluster. p99-Lesezugriffe auf dem 99. Perzentil liegen sub-100ms, sogar auf Cold Paths.
  3. Die Kosten sind durch die Anfragenanzahl begrenzt, nicht durch Instanzstunden. Ein Node-Server, der nach Stunden abgerechnet wird, kostet das Gleiche, ob er 100 oder 100.000 Anfragen bedient. Workers werden pro Request abgerechnet – mit einem großzügigen Free-Tier und vorhersehbaren Preisen pro Million darüber. Die aktuellen Tarife finden Sie auf der Seite Workers Pricing.

Ich habe ein Mobile-App-Backend auf diesem Stack sieben Monate lang mit Spitzenlast von 1,1M Requests/Tag betrieben, als einzelner Solo-Entwickler, und habe nie einen Pager benötigt. Im Folgenden finden Sie die Architektur, die Zahlen und den Code, der diese Ergebnisse liefert.

Was „Edge" für Mobile Nutzer tatsächlich bedeutet

Der Mobile Client weiß oder interessiert sich nicht dafür, dass er mit einer Edge-Runtime spricht. Aus Sicht des Clients sendet er eine HTTPS-Anfrage und erhält eine JSON-Antwort. Das Edge-Routing geschieht transparent in Cloudflares Netzwerk. Der Vorteil zeigt sich als Verbesserung der Tail-Latenz – p99 TTFB auf der produktiven Mobile API bei 1,1M req/Tag lag global bei 92ms, verglichen mit 410ms für dieselbe API, die zuvor auf einer einzelnen EC2-Instanz in us-east-1 gehostet wurde. Die 4-fache Verbesserung der Tail-Latenz ist das, was Nutzer als „die App fühlt sich schnell an" empfinden, selbst auf schlechten Netzen.

Derselbe Worker kann bei Bedarf auch Geofencing-Routing durchführen: Workers-Paid-Kunden können Regionsfilterung konfigurieren, sodass eine Anfrage, die von einer EU-IP stammt, nur in EU-Rechenzentren ausgeführt wird. Dies ist wichtig für GDPR-gebundene Apps, bei denen die Datenlokalisierung eine Compliance-Anforderung ist.

Die vier Bindings, die Sie tatsächlich nutzen

Mobile Backends auf Workers brauchen nicht jedes Cloudflare-Produkt. Sie brauchen vier, die zweckgemäß eingesetzt werden.

D1 für relationale Daten (Auth, Abrechnung, Subscriptions)

D1 ist Cloudflares verteilte SQLite-Datenbank – lesen Sie die D1-Dokumentation für die gesamte Oberfläche. Für ein Mobile-App-Backend hält D1 Nutzer, Sessions, Subscriptions, In-App-Käufe, Push-Tokens und alle anderen relationalen Daten. Lesezugriffe sind sub-millisekundig, wenn sie mit dem Worker collocated sind; Schreibzugriffe sind dauerhaft und repliziert.

Das Schema für ein typisches Mobile SaaS passt in 12 Tabellen. Meines enthielt: users, sessions, subscriptions, push_tokens, devices, in_app_purchases, support_tickets, feature_flags, audit_log, content_versions, ab_assignments und webhook_events. Gesamtgröße: 18MB. D1s 10GB-pro-Datenbank-Limit ist kein Problem, bis Sie eine Größe erreichen, die Sharding erfordert.

KV für Cache + Konfiguration (Feature Flags, Nutzer-Einstellungen)

Cloudflare KV ist eventuell konsistenter Key-Value-Speicher. Die eventuelle Konsistenz (60-Sekunden-Propagationsfenster global) ist in Ordnung für Feature Flags, Nutzerpräferenzen, A/B-Test-Zuweisungen und Konfiguration – alles, wo das Lesen eines leicht veralteten Wertes akzeptabel ist. KV-Lesezugriffe sind bis zu 10M pro Tag im Free-Tier kostenlos, was die meisten Mobile Backends auf unbestimmte Zeit abdeckt.

Das Muster, das am längsten brauchte, bis es sich einschlich: KV nicht für etwas verwenden, wo Konsistenz wichtig ist. Subscription-Status, Zahlungsstatus und Authentifizierungsdaten gehören in D1. Feature Flags, Theme-Präferenzen und der Onboarding-Schritt-Index gehören in KV.

R2 für Medien (Avatare, Fotos, Exporte)

R2 ist S3-kompatibler Objektspeicher ohne Ausgangsgebühren. Für ein Mobile-App-Backend hält R2 nutzerhochgeladene Medien: Profilavatare, Foto-Anhänge, exportierte Berichte, generierte PDFs, Sprachnotizen. Das Zero-Egress-Modell ist wichtig, weil Mobile Clients bandbreitenbeschränkt sind; Sie möchten nicht pro Byte bezahlen, um ein 2MB-Avatar an jeden aktiven Nutzer auszuliefern.

R2s Preisgestaltung ist unkompliziert: $0,015/GB gespeichert pro Monat, keine Ausgangsgebühren. 10GB Nutzerfotos kosten $0,15/Monat. Dieselbe Workload auf S3 würde $0,23/Monat für Speicher plus ca. $90/Monat für Ausgabe bei 1TB Transfer kosten.

Durable Objects für Echtzeit (Presence, Live Sync)

Durable Objects sind single-threaded JavaScript-Worker, die Zustand im Speicher halten und den Zugriff darauf über alle Clients koordinieren. Für ein Mobile-App-Backend ermöglichen Durable Objects Echtzeit-Features: Presence-Indikatoren (wer ist online), kollaboratives Editieren, Live-Benachrichtigungen, Sync-Zustand über Geräte hinweg.

Das Referenzmuster ist ein Durable Object pro Nutzer, das den In-Memory-Zustand hält, mit WebSocket-Verbindungen vom Mobile Client für Live-Updates. DOs werden pro Request und pro Dauer abgerechnet; budgetieren Sie mit $0,15–$0,50/Monat pro 1M DO-Requests.

Die Einschränkung, die zuerst schmerzt: Durable Objects sind single-threaded. Wenn Sie ein DO erstellen, das synchrones CPU-Work auf dem Hot Path macht (Bildverarbeitung, große JSON-Serialisierung, ML-Inferenz), wartet jeder konkurrierende WebSocket-Client auf diesem DO. Die Lösung ist, schwere Arbeit in einem regulären Worker zu erledigen und das DO nur die Zustandskoordination übernehmen zu lassen. Das ist dasselbe mentale Modell wie eine single-threaded Node Event Loop – nur nicht-blockierendes I/O.

Die 50ms p99 Cold-Start-Zahl (Und wie wir sie gemessen haben)

Die Headline-Zahl für Workers ist die Cold-Start-Latenz. Die Cloudflare-Marketingseite behauptet „nahezu null Cold Starts" – das stimmt, ist aber vage. Hier ist, was wir tatsächlich gemessen haben.

Benchmark-Methodik

Ich habe die Produktiv-API mit Timing-Headern (X-Worker-Start, X-Worker-Duration) instrumentiert und 30 Tage lang jeden Cold Start aufgezeichnet. Ein Cold Start ist definiert als die erste Anfrage an einen Worker nach einem 15-minütigen Leerlauf-Fenster (das Standard-Intervall für das Workers-Isolate-Recycling). Warme Anfragen sind alles dazwischen.

Cold-Start-Verteilung (p50/p90/p99)

Über 30 Tage wurden 18.400 Cold Starts an 14 API-Endpunkten aufgezeichnet:

  • p50: 18ms
  • p90: 38ms
  • p99: 50ms
  • p99.9: 84ms
  • Max: 220ms (ein bestimmter Endpunkt mit einem 1,2MB großen Import-Graph)

Zum Vergleich: Ein Node-Express-Server auf AWS Lambda hatte p99 Cold Starts von 1.400ms im selben Zeitfenster. V8-Isolates sind etwa 30-mal schneller beim Cold Start als containerbasierte serverlose Dienste, weil es keine Container-Orchestrierung, kein Docker Pull und kein zu bootendes OS gibt.

Der 220ms-Ausreißer an einem bestimmten Endpunkt wurde auf einen schweren Import-Graphen zurückgeführt – Stripe SDK + 4 Drizzle-Schemas + 3 benachbarte Server Functions in einer Datei. Die Lösung (Route-Level-Code-Splitting über dynamische Imports) ist ein separater Postmortem, der einen eigenen Artikel wert ist. Die Headline-Zahl für einen gut architektierten Worker ist 50ms p99.

Warum die Bundle-Größe den Cold Start bestimmt

Die Cold-Start-Kosten eines Workers skalieren ungefähr linear mit der Größe seines kompilierten JavaScript-Bundles. Bei 100KB können Sie den Cold Start nicht messen; bei 500KB sind es 30–40ms; bei 1MB sind es 80–120ms; bei 5MB stoßen Sie an das Workers-Bundle-Größenlimit und Cold Starts werden unzuverlässig.

Die Implikation für Mobile-Backend-Autoren: Halten Sie den Import-Graphen jedes Workers schmal. Wenn Sie Stripe nur in einer Server Function brauchen, importieren Sie Stripe dynamisch innerhalb dieser Funktion, anstatt oben in einem gemeinsamen Modul. TanStack Ships Server-Functions-Template erzwingt dies standardmäßig – jede Routengruppe erhält ihr eigenes Bundle über den Lazy-Module-Loader der Route.

Reale Architektur: TanStack Ship Reference Stack

Das Mobile-Backend, das in TanStack Ship ausgeliefert wird, nutzt TanStack Start Server Functions für die API-Oberfläche. Jede Routengruppe ist eine Server Function, die nur die Bindings importiert, die sie braucht.

typescript
// app/server/auth.ts — Mobile-Auth-Endpunkt
import { createServerFileRoute } from '@tanstack/start/server';
import { db } from '~/lib/db';
import { users, sessions, devices } from '~/lib/schema';
import { eq } from 'drizzle-orm';
import { signJWT } from '~/lib/jwt';

export const ServerRoute = createServerFileRoute('/api/mobile/auth/login').methods({
  POST: async ({ request }) => {
    const { email, password, deviceId, pushToken } = await request.json();

    // D1-Lookup — sub-millisekundig am Edge
    const user = await db.select().from(users).where(eq(users.email, email)).get();
    if (!user) return Response.json({ error: 'invalid_credentials' }, { status: 401 });

    const valid = await verifyPassword(password, user.passwordHash);
    if (!valid) return Response.json({ error: 'invalid_credentials' }, { status: 401 });

    // JWT für den Mobile Client ausstellen
    const jwt = await signJWT({ userId: user.id, deviceId });

    // Session + Gerät in einer einzigen D1-Transaktion persistieren
    await db.batch([
      db.insert(sessions).values({
        id: jwt.id,
        userId: user.id,
        deviceId,
        createdAt: Date.now(),
        expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,
      }),
      db.insert(devices).values({
        id: deviceId,
        userId: user.id,
        pushToken,
        lastSeenAt: Date.now(),
      }).onConflictDoUpdate({
        target: devices.id,
        set: { pushToken, lastSeenAt: Date.now() },
      }),
    ]);

    return Response.json({ jwt, userId: user.id });
  },
});

Das ist ein Endpunkt. Auth, Session-Persistenz und Geräteregistrierung in einer einzigen D1-Transaktion. Kein Node, kein separater Auth-Service, kein Lambda Cold Start.

Code: Push-Benachrichtigungs-Dispatch über Durable Object

Das Echtzeit-Element des Mobile-Backends ist der Push-Benachrichtigungs-Dispatch. Das Muster: Ein Durable Object pro Nutzer hält die Online-Geräte des Nutzers und dispatcht Push-Benachrichtigungen an alle.

typescript
// app/server/push.ts — Durable Object pro Nutzer für Push-Routing
import { DurableObject } from 'cloudflare:workers';

interface Device {
  id: string;
  pushToken: string;
  platform: 'ios' | 'android';
  lastSeenAt: number;
}

export class PushRouter extends DurableObject {
  devices: Map<string, Device> = new Map();

  async registerDevice(device: Device): Promise<void> {
    this.devices.set(device.id, device);
    // In D1 persistieren für Cold-Start-Wiederherstellung
    await this.env.DB.prepare(
      'INSERT OR REPLACE INTO devices (id, push_token, platform, last_seen_at) VALUES (?, ?, ?, ?)'
    ).bind(device.id, device.pushToken, device.platform, Date.now()).run();
  }

  async dispatch(payload: { title: string; body: string; data?: unknown }): Promise<void> {
    const routes: Promise<Response>[] = [];

    for (const device of this.devices.values()) {
      if (device.platform === 'ios') {
        routes.push(this.sendAPNs(device.pushToken, payload));
      } else {
        routes.push(this.sendFCM(device.pushToken, payload));
      }
    }

    await Promise.allSettled(routes);
  }

  private async sendAPNs(token: string, payload: any): Promise<Response> {
    return fetch('https://api.push.apple.com/3/device/' + token, {
      method: 'POST',
      headers: {
        authorization: `bearer ${this.env.APNS_KEY}`,
        'apns-topic': this.env.APNS_BUNDLE_ID,
        'apns-push-type': 'alert',
      },
      body: JSON.stringify({ aps: { alert: payload } }),
    });
  }

  private async sendFCM(token: string, payload: any): Promise<Response> {
    return fetch('https://fcm.googleapis.com/fcm/send', {
      method: 'POST',
      headers: {
        authorization: `key=${this.env.FCM_KEY}`,
        'content-type': 'application/json',
      },
      body: JSON.stringify({ to: token, notification: payload }),
    });
  }
}

Das Durable Object hält die In-Memory-Geräte-Map, persistiert nach D1 für Cold-Start-Wiederherstellung und verteilt Pushes an APNs und FCM parallel. Der Mobile Client erreicht dieses Durable Object über ein WebSocket, sodass die Online-Geräte des Nutzers ohne Polling synchron bleiben.

Der Webhook-Receiver für Stripe (oder einen anderen Zahlungsabwickler) ist ein paralleler Worker, der in eine D1-Warteschlangentabelle schreibt; das Durable Object leert die Warteschlange und dispatcht Pushes. Diese Trennung bedeutet, dass ein Stripe-Ausfall nicht die Push-Zustellung blockieren kann und umgekehrt. Jede Komponente fällt unabhängig voneinander aus.

Wie die Teile in der Produktion zusammenarbeiten

Das Mobile-Backend hat vier Request-Einstiegspunkte, die jeweils durch denselben Cloudflare Worker geroutet werden, aber verschiedene Bindings ausführen:

  1. Mobile-API-Anfragen – HTTPS-REST-Endpunkte unter /api/mobile/*, verarbeitet von TanStack Start Server Functions, lesend aus D1 und KV.
  2. Stripe-Webhooks – POST-Endpunkt unter /api/webhooks/stripe, mit Idempotenz-Key, schreibend nach D1 mit einem Durable Object, das Exactly-Once-Verarbeitung erzwingt.
  3. WebSocket-Verbindungen – /api/mobile/ws, upgradend zu Durable Object pro Nutzer, mit Verteilung von Push-Benachrichtigungen und Live-State.
  4. Statische Assets (selten bei Mobile Backends) – R2-basierte statische Dateien für herunterladbare Berichte, exportierte CSVs, generierte PDFs.

Alle vier Einstiegspunkte teilen sich dieselbe Cloudflare-Worker-Codebasis und dieselben Bindings (D1, R2, KV, Durable Objects). Die Codebasis ist ein TypeScript-Projekt; die wrangler.toml deklariert die Bindings einmal. Es gibt keinen separaten „WebSocket-Service" oder „API-Service" – nur einen Worker mit mehreren Route-Handlern.

Kostenrechnung: 1M req/Tag für $5/Monat

Die Hosting-Rechnung für das Mobile-Backend bei 1,1M Requests/Tag Spitzenlast (Rechnung April 2026):

PostenNutzungKosten
Cloudflare Workers Paid-Plan33M Requests/Monat$5,00
Cloudflare D125M Lesezugriffe, 200k Schreibzugriffe$0,00 (inkludiert)
Cloudflare KV3M Lesezugriffe, 100k Schreibzugriffe$0,00 (inkludiert)
Cloudflare R28GB gespeichert, 2TB Ausgabe$0,12
Cloudflare Durable Objects800k Requests$0,15
APNs / FCM Push200k Pushes$0,00
Gesamt$5,27/Monat

Die dominante Kostenposition ist der Workers Paid-Plan mit $5/Monat, der bis zu 30M Requests abdeckt. Über 30M berechnet Workers $0,30 pro zusätzliche Million. Bei 100M Requests/Monat beträgt die Rechnung $26/Monat. Immer noch günstiger als eine einzelne t3.medium EC2-Instanz, die rund um die Uhr läuft.

Der Mobile Client selbst erzeugt keine Workers-Kosten – nur API-Aufrufe tun es. Inaktive Nutzer (die Mehrheit in jeder Mobile App) kosten genau $0, um bedient zu werden.

Die vollständige Rechnungsskalierungskurve, die ich von Oktober 2025 bis April 2026 beobachtet habe:

MonatReq/TagWorkersD1KVR2DOGesamt
Okt. 202512k$0$0$0$0,03$0$0,03
Dez. 2025180k$0$0$0$0,06$0,04$0,10
Feb. 2026620k$0$0$0$0,09$0,09$0,18
Apr. 20261,1M$5,00$0$0$0,12$0,15$5,27

Die nichtlineare Kostenkurve (3 Größenordnungen beim Traffic, ~175-fach bei den Kosten) ist das Hauptaussage. Ein Node-Server, der auf diese Kurve skaliert wäre, hätte im April ca. $80–$120/Monat gekostet (zwei t3.medium-Instanzen plus RDS Postgres). Die Kostendifferenz finanziert ein Jahr inkrementelle Produktentwicklung.

Ehrliche Abwägungen: Wo Workers für Mobile verliert

Ich werde nicht so tun, als gewänne Workers in jedem Mobile-Backend-Vergleich. Vier Fälle, in denen Sie eine andere Stack-Wahl treffen sollten:

  • Lange laufende CPU-Arbeit. Workers haben ein 30-Sekunden-Wanduhr-Limit für eine einzelne Invokation (15s im Free-Tier). Wenn Ihre Mobile API ML-Inferenz, Video-Transcoding oder eine andere CPU-gebundene Aufgabe über 30 Sekunden durchführen muss, brauchen Sie eine andere Runtime. Workers AI führt Modelle in unter 30s für die meisten Inferenzen aus; alles andere braucht eine Warteschlange + dediziertes Compute.
  • State-heavy Workloads im Speicher. Workers haben ein 128MB-Speicherlimit pro Isolate. Wenn Ihre API einen großen In-Memory-Cache hält, eine schwere ORM ausführt oder große Payloads verarbeitet, werden Sie an das Limit stoßen. Die Lösung ist, große Responses über die Streams API zu streamen und schwere Verarbeitung aus dem Anfragepfad herauszuhalten.
  • iOS-NSURLSession-Eigenheiten am Edge. iOS-Clients, die URLSession verwenden, wiederholen manchmal fehlgeschlagene Anfragen mit HTTP/1.1-Fallback, was zu unerwarteten doppelten POSTs an /checkout-artige Endpunkte führen kann. Die Lösung ist ein Idempotency-Key-Header an jedem zustandsändernden Endpunkt und eine D1-Idempotency-Tabelle, die auf dem Header-Wert basiert.
  • Apps mit strenger regulatorischer Datenlokalisierung. Workers laufen in Cloudflares Edge-Netzwerk (330+ Städte). Wenn Sie benötigen, dass Daten in einer bestimmten Jurisdiktion bleiben (nur EU, nur USA), erfüllt Workers' Standard-Routing möglicherweise nicht die Compliance. Workers-Paid-Kunden können Regionsfilterung pro Route konfigurieren, aber das ist ein Konfigurationsaufwand, keine Standardeinstellung.

Für einen detaillierteren Vergleich mit Supabase und Firebase als Mobile Backends lesen Sie unsere TanStack Ship vs Supastarter- und TanStack Ship vs Makerkit-Analysen.

Entscheidungsbaum: Wann Workers, wann Supabase, wann reines Node

Wählen Sie Cloudflare Workers + D1/R2/KV/DO, wenn:

  • Ihre Mobile API request/response- oder WebSocket-basiert ist mit Antwortzeiten unter 30 Sekunden
  • Ihre Nutzer global verteilt sind und Edge-Latenz wichtig ist
  • Ihr Budget bei geringer Skalierung eng ist und Sie vorhersehbares Kostenwachstum wünschen
  • Sie keine Node-exklusiven Pakete oder lange laufende CPU benötigen

Wählen Sie Supabase oder Firebase, wenn:

  • Sie ein verwaltetes Postgres (Supabase) oder Firestore (Firebase) mit einem eingebauten SDK für Ihre Mobile-Plattform benötigen
  • Sie Echtzeit-Subscriptions ohne eigenen WebSocket-Kleber wollen
  • Ihr Team bereits proficient in einem dieser Ökosysteme ist

Wählen Sie Reines Node (Express, Fastify, Hono) auf Fly.io oder Railway, wenn:

  • Sie Pakete benötigen, die von Node-Built-ins abhängen (sharp für Bildverarbeitung, native Bindings)
  • Ihre API lange laufende Streaming-Responses hat
  • Sie es gewohnt sind, einen Server zu verwalten und volle Kontrolle wollen

Für einen Preisvergleich über diese Stacks hinweg lesen Sie die TanStack Ship Preisseite.

FAQ

Unterstützt Cloudflare Workers WebSockets für Mobile Apps? Ja. Die WebSocket-API ist stabil auf Workers und unterstützt bidirektionales Echtzeit-Messaging. Der Mobile Client verwendet URLSessionWebSocketTask auf iOS oder OkHttp WebSocket auf Android. Lesen Sie die WebSocket-Dokumentation.

Kann D1 konkurrierende Schreibzugriffe von vielen Mobile Clients bewältigen? Ja, mit Einschränkungen. D1 verwendet den SQLite-WAL-Modus und serialisiert Schreibzugriffe pro Datenbank. Für hochschreiblastige Workloads (>1k Schreibzugriffe/Sekunde dauerhaft) müssen Sie entweder über mehrere D1-Datenbanken sharden oder auf eine andere Speicherschicht umsteigen. Für die meisten Mobile Backends, die weit unter 1k Schreibzugriffen/Sekunde liegen, ist D1 in Ordnung.

Wie sieht es mit der Zuverlässigkeit von Push-Benachrichtigungen aus? APNs und FCM garantieren beide mindestens-einmal-Zustellung, aber nicht höchstens-einmal. Doppelte Pushes kommen vor; der Mobile Client muss nach einem notificationId-Feld im Payload deduplizieren. Das Durable-Object-Muster oben handhabt die serverseitige Deduplizierung, indem es die letzte zugestellte notificationId pro Gerät verfolgt.

Wie handhaben Sie Auth-Refresh-Token im Mobile App? Issuen Sie ein kurzlebiges (15-Min.) Access-JWT und ein langlebiges (30-Tage) Refresh-Token. Speichern Sie das Refresh-Token im iOS Keychain oder in Android EncryptedSharedPreferences. Der Refresh-Endpunkt validiert das Refresh-Token gegen eine D1-Sessions-Tabelle, rotiert es und issued ein neues Access-JWT. Standard-OAuth-2.0-Muster, passt sauber in einen Worker.

Was passiert, wenn Cloudflare einen Ausfall hat? Cloudflares Statusseite zeigt historische Uptime von 99,99%+ für Workers. Für geschäftskritische Mobile Apps ist die Antwort Multi-Region-Fallback: Replizieren Sie die API auf AWS Lambda oder Fly.io und routen Sie über DNS-Health-Checks. Ich habe das für keines meiner Mobile Apps implementiert, weil der Kosten-Nutzen es noch nicht gerechtfertigt hat.

Brauche ich TanStack Start, um Workers zu nutzen, oder kann ich Plain Workers verwenden? Plain Workers (die fetch-Handler-API) funktionieren für jedes Backend. TanStack Start ist die Konvention für Routing, Server Functions und End-to-End-Typisierung. Wenn Ihr Team Hono oder itty-router bevorzugt, funktionieren diese genauso gut. Lesen Sie die Workers-Dokumentation für das minimale Setup.

Wie handhaben Sie Rate Limiting am Edge? Jeder Worker-Route hat ein per-IP- und per-User-Rate-Limit, erzwungen über ein Durable Object, das einen Sliding-Window-Zähler hält. Limits werden alle 60 Sekunden zurückgesetzt. Das Standard-Limit beträgt 100 req/min pro User für authentifizierte Endpunkte und 30 req/min pro IP für nicht-authentifizierte. Über dem Limit gibt der Worker 429 mit einem Retry-After-Header zurück. Kein externer API-Gateway erforderlich.

Was ist mit Analytics und Observability für die Mobile API? Workers Analytics Engine (noch Beta in 2026) ist der günstige Weg: Schreiben Sie einen einzelnen writeDataPoint()-Aufruf pro Request und zahlen Sie $0,05 pro Million aufgenommener Datenpunkte. Für tiefere Traces können Cloudflare Logs nach R2 gestreamt und mit wrangler tail während der Entwicklung oder einem Drittanbieter-APM während Incidents geparst werden. Vermeiden Sie es, große Request/Response-Bodies zu loggen – jedes geloggte Byte zählt gegen Ihre Workers-Bundle-Limits, wenn Sie im Speicher puffern.

Kann das Mobile Backend mit internen Services hinter einem VPN kommunizieren? Workers können ein privates VPC nicht direkt erreichen. Für Mobile Backends, die interne APIs auf AWS oder GCP aufrufen müssen, ist das Standardmuster ein ausgehender HTTP-Aufruf über das öffentliche Internet mit mTLS-Authentifizierung. Cloudflares Service-Bindings ermöglichen es einem Worker, einen anderen Worker direkt aufzurufen, ohne über das öffentliche Internet zu gehen, was nützlich ist, um ein Mobile Backend auf mehrere Workers aufzuteilen.

Wie sieht der Migrationspfad aus, wenn ich über Workers hinauswachie? Die beiden Pfade, die ich in der Produktion funktionieren gesehen habe: (1) schweren Zustand aus Durable Objects in ein verwaltetes Postgres (Neon, Supabase) auslagern und Workers als API-Layer behalten; (2) den gesamten Stack auf eine containerbasierte Runtime (Fly.io, Railway) umziehen, wenn Sie lange laufende CPU oder >128MB Speicher benötigen. Die TanStack-Start-Codebasis auf Workers portiert sauber auf beide Ziele, weil das Server-Functions-Muster portabel ist – nur die Binding-Deklarationen ändern sich.

Schluss

Ein Mobile-App-Backend auf Cloudflare Workers ist real, produktionsreif und günstig. Die Architektur sind vier Bindings – D1, R2, KV, Durable Objects – verdrahtet in je einem Worker pro Routengruppe. 50ms p99 Cold Start. $5,27/Monat bei 1,1M Requests/Tag. Ein einzelner Solo-Entwickler, sieben Monate, ohne Pager.

Wenn Sie dieses Quartal ein Mobile SaaS starten und Ihr Backend in das Request/Response- oder WebSocket-Muster passt, klonen Sie TanStack Ship und haben Sie den Mobile-Auth-Endpunkt in unter einer Stunde am Laufen. Die vier Bindings und die Deployment-Pipeline sind bereits verdrahtet.