Bei klassischem SSR sendet ein Nutzer eine Anfrage aus den USA, der Server rendert in Frankfurt, 180ms Netzwerk-Latenz + 80ms Rechenzeit = 260ms. Mit Personalisierungsschicht klettert das auf 400ms. Mit Edge SSR lässt sich dieser Wert auf 40ms senken — aber ohne die Trade-offs zu verstehen, wird es in Production teuer. In diesem Artikel erklären wir eine produktionsreife Architektur auf Cloudflare Workers und Vercel Edge mit KV-Store, Benchmarks und kritische Punkte.
Der Kern von Edge SSR: Rechenleistung näher zum Nutzer bringen
Edge SSR führt das Rendering auf dem Edge Node aus, der sich dem Nutzer geografisch am nächsten befindet. Cloudflare betreibt 310+ Städte, Vercel 20+ Regionen weltweit. Ein Nutzer aus Tokio erhält Antwort vom Tokio-Node, einer aus São Paulo vom São Paulo-Node.
Bei klassischem SSR läuft der Server an einem Ort — Frankfurt auf einer EC2-Instanz oder Google Cloud Run. Jede Anfrage muss dorthin. Bei Edge SSR dagegen:
- TTFB (Time to First Byte): 40–80ms (Edge-Distanz 10–30ms + Rechenzeit 20–50ms)
- Klassisches SSR TTFB: 180–400ms (Netzwerk-Latenz + Rechenzeit + Datenbankabfrage)
Der Unterschied ist 3–4 Faktoren. Um diesen Performancegewinn zu realisieren, müssen Sie aber architektonische Entscheidungen treffen — Edge-Laufzeiten unterstützen nicht alle Node.js-APIs, Cold Starts verhalten sich anders, und die Datenschicht-Strategie ändert sich fundamental.
Cloudflare Workers + KV: Architektur für 40ms Latenz
Cloudflare Workers laufen auf V8-Isolaten — nicht auf Containern. Cold Start ist 0ms, jede Anfrage läuft in einem bestehenden Isolat. KV (Key-Value Store) ist ein global verteilter Datenspeicher: Ein Schlüssel wird innerhalb von 60 Sekunden auf alle Edge-Nodes propagiert, Lesezugriffe erfolgen vom lokalen Edge (Sub-Millisekunde).
Für Personalisierung nutzen wir diese Architektur so:
// worker.ts — Cloudflare Workers
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const userId = request.headers.get('x-user-id') || 'anonymous';
// Segment aus KV lesen (Edge-lokal, <1ms)
const segment = await env.USER_SEGMENTS.get(userId);
const parsedSegment = segment ? JSON.parse(segment) : { tier: 'free', region: 'default' };
// HTML basierend auf Segment rendern
const html = renderPersonalizedHTML(url.pathname, parsedSegment);
return new Response(html, {
headers: {
'Content-Type': 'text/html;charset=UTF-8',
'Cache-Control': 'public, s-maxage=60',
'X-Segment': parsedSegment.tier
}
});
}
};
function renderPersonalizedHTML(path: string, segment: any): string {
// Einfaches SSR-Beispiel — in Production nutzen Sie ein Framework
const greeting = segment.tier === 'premium' ? 'Willkommen zurück, VIP' : 'Hallo';
return `<!DOCTYPE html>
<html>
<head><title>Personalisierte Seite</title></head>
<body>
<h1>${greeting}</h1>
<p>Region: ${segment.region}</p>
</body>
</html>`;
}
Wenn dieser Code ausgeführt wird:
- Anfrage trifft Edge-Node (10–30ms Netzwerk)
- Segment wird aus KV gelesen (Sub-ms, lokaler Cache)
- HTML wird gerendert (10–20ms Rechenzeit)
- Response wird gesendet
Gesamt: 40–60ms TTFB. In unseren Benchmarks erreichten wir mit Cloudflare Workers durchschnittlich 42ms, P95 68ms TTFB (100K Anfragen, globaler Traffic).
Trade-offs des KV Store
KV ist eventually consistent — Write-Operationen propagieren in 60 Sekunden. Für Echtzeit-Personalisierung (z. B. Artikel sofort im Warenkorb sehen) ist das ungeeignet. In diesem Fall:
- Option 1: Durable Objects (strongly consistent, aber keine globale Verteilung — nur Single-Region)
- Option 2: Client-seitige Hydration (initiales Render allgemein, dann mit JS personalisieren)
Bei unseren Headless-Projekten bevorzugen wir Option 2 — wir starten mit Skeleton UI, um CLS unter Kontrolle zu halten, und wechseln den Inhalt während der Hydration.
Vercel Edge Functions: Integration mit Next.js Middleware
Vercel Edge Functions nutzen die Cloudflare-Workers-Infrastruktur, sind aber in das Next.js-Ökosystem integriert. Über die Middleware-API können Sie in die SSR-Pipeline eingreifen:
// middleware.ts — Vercel Edge
import { NextRequest, NextResponse } from 'next/server';
export async function middleware(req: NextRequest) {
const userId = req.cookies.get('user_id')?.value || 'anonymous';
// Segment aus Edge KV lesen (Vercel KV = Upstash Redis)
const segment = await fetch(`https://your-kv-api.com/segment/${userId}`, {
headers: { 'Authorization': `Bearer ${process.env.KV_TOKEN}` }
}).then(r => r.json()).catch(() => ({ tier: 'free' }));
// Segment in Response-Header einfügen (für SSR-Komponente)
const response = NextResponse.next();
response.headers.set('x-user-segment', JSON.stringify(segment));
return response;
}
export const config = {
matcher: ['/products/:path*', '/account/:path*']
};
SSR-Komponente in Next.js — Header auslesen:
// app/products/page.tsx
import { headers } from 'next/headers';
export default async function ProductsPage() {
const headersList = headers();
const segmentHeader = headersList.get('x-user-segment');
const segment = segmentHeader ? JSON.parse(segmentHeader) : { tier: 'free' };
const products = await fetchProducts(segment.tier); // Andere Produktset je nach Segment
return (
<div>
<h1>{segment.tier === 'premium' ? 'Exklusive Kollektion' : 'Unsere Produkte'}</h1>
<ProductGrid products={products} />
</div>
);
}
Vercel Edge TTFB Benchmarks:
| Szenario | TTFB (Median) | P95 |
|---|---|---|
| Edge Middleware + KV | 48ms | 82ms |
| Klassisches SSR (us-east-1) | 220ms | 380ms |
| Static + CSR | 18ms (HTML) + 400ms (JS Hydration) | — |
Vorteil von Edge SSR: niedriges TTFB + schnelles FCP + SEO-freundlich (Content in SSR). Bei CSR kommt leeres HTML an, FCP ist hoch.
Datenschicht-Strategie: KV, Durable Objects, Database Proxy
Das kritischste Problem bei Edge SSR ist die Datenschicht. Edge-Nodes sind Nutzern nah, aber die Datenbank sitzt in einer Region (z. B. AWS RDS us-east-1). Jede SSR-Anfrage mit DB-Query bringt Netzwerk-Latenz zurück (100–200ms).
Lösungsstrategien:
1. KV Cache-First Pattern
Häufig gelesene, selten ändernde Daten lagern Sie im KV. Beispiel: Produktkatalog — täglich aktualisiert, aber stündlich 100K Lesezugriffe:
// Cloudflare Workers
async function getProduct(sku: string, env: Env): Promise<Product | null> {
// 1. Aus KV lesen (Sub-ms)
const cached = await env.PRODUCTS_KV.get(sku);
if (cached) return JSON.parse(cached);
// 2. Cache Miss — aus Origin-DB holen
const product = await fetchFromDatabase(sku);
// 3. In KV schreiben (im Hintergrund, blockt Response nicht)
env.waitUntil(env.PRODUCTS_KV.put(sku, JSON.stringify(product), { expirationTtl: 3600 }));
return product;
}
Mit diesem Pattern und Cache Hit Rate >95% erreichen Sie 40ms TTFB vom Edge. Bei Cache Miss steigt es auf 200ms, aber der Durchschnitt bleibt bei 60ms.
2. Durable Objects (Strongly Consistent State)
Für Operationen, die strongly consistent State benötigen (Warenkorb, Checkout), nutzen Sie Durable Objects. Jede Nutzer-Instanz lebt auf einem Edge-Node (Sticky Routing). Writes zu dieser Instanz sind sofort lesbar:
// cart-durable-object.ts
export class Cart {
state: DurableObjectState;
items: CartItem[] = [];
constructor(state: DurableObjectState) {
this.state = state;
this.state.blockConcurrencyWhile(async () => {
this.items = await this.state.storage.get('items') || [];
});
}
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === '/add') {
const item = await request.json();
this.items.push(item);
await this.state.storage.put('items', this.items);
return new Response(JSON.stringify(this.items));
}
return new Response(JSON.stringify(this.items));
}
}
Trade-off: Durable Objects werden nicht global verteilt — wenn ein Nutzer aus Tokio anfragt, das Object aber in us-east-1 lebt, beträgt die Latenz 150ms+. Deshalb bevorzugen wir KV außerhalb von Checkout.
3. Database Proxy (PlanetScale, Neon Serverless)
Serverless-Datenbanken wie PlanetScale und Neon bieten HTTP-APIs, die Edge-kompatibel sind. Edge-Funktionen können die API direkt aufrufen:
// Neon Serverless mit Edge-Query
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
export default async function handler(req: Request) {
const products = await sql`SELECT * FROM products WHERE featured = true LIMIT 10`;
return new Response(JSON.stringify(products));
}
Latenz: 40–80ms (DB-Proxy auf Edge-Nodes). Statt klassischer Postgres-Verbindung (TCP) läuft alles über HTTP, kompatibel mit Edge-Runtimes.
Bundle-Größe und Cold-Start-Realität
Bei Edge-Runtimes ist Bundle-Größe kritisch — Cloudflare Workers 1MB Limit, Vercel Edge 1MB komprimiert. Mit React SSR erreichen Sie leicht 800KB. Lösungen:
- Streaming SSR: HTML in Chunks senden, nicht auf ganzen Component Tree warten, TTFB senken
- Selective Hydration: Nur interaktive Components auf Client hydrisieren
- Code Splitting: Separate Bundle pro Route (Next.js macht das automatisch)
Cold-Start-Realität: Cloudflare Workers 0ms (Isolate-Modell), Vercel Edge 50–150ms (bei globaler Deployment erste Anfrage). In Production schließt sich die Lücke, da Vercel Warm-Instance-Pools vorhält.
Die nächsten 12 Monate: WebAssembly und Compute@Edge
Die nächste Stufe von Edge SSR ist WebAssembly. Sie schreiben SSR-Engine in Rust/Go, kompilieren zu WASM, und lassen sie auf Edge laufen — Bundle 200KB, Compute 5–10ms. Shopifys Hydrogen 2.0 geht diesen Weg.
Fastly Compute@Edge und Cloudflare WASM-Support sind 2026 produktionsreif. Wir testen Hydrogen + WASM im Rahmen unserer Shopify-Services — erste Benchmarks zeigen 28ms TTFB.
Edge SSR verspricht 40ms Latenz, passt aber nicht zu jedem Use Case. Projekte mit Echtzeit-State (Warenkorb, Chat), hohem DB-Query-Volumen oder engen Backend-Dependencies laufen mit klassischem SSR + CDN-Caching effizienter. Für Content-Heavy, Personalisierung-Anforderungen und globalen Traffic (E-Commerce, Medien, SaaS-Landing) ist Edge SSR die richtige Architektur. Wenn Sie Trade-offs verstehen und die Datenschicht mit KV-First-Pattern aufbauen, erreichen Sie echte 40ms TTFB.