Herkömmliches Server-Side Rendering auf Origin-Servern bedeutet durchschnittlich 200–400ms Latenz. Mit HTML-Caching auf CDN-Edges sinkst du auf 20–50ms, verlierst aber Personalisierung. Edge SSR bricht diesen Tradeoff auf: Du bekommst Personalisierung UND Response unter 40ms. Möglich wird das durch Edge Runtimes wie Cloudflare Workers und Vercel Edge plus verteilter KV-Speicher. Die Frage „Cache oder Personalisierung?" verschwindet — du bekommst beides.
Warum Edge SSR jetzt kritisch ist
Seit 2025 ist Chromes INP-Metrik Teil der Core Web Vitals. Eine Server-Response über 200ms kann INP allein kaputt machen. Jeder Request zum Origin kostet 150–300ms, wegen physikalischer Distanz und Cold Starts. Edge Runtimes eliminieren diesen Engpass: Dein Code läuft im nächstgelegenen POP (Point of Presence), Daten kommen aus dem regionalen KV-Store in 5–15ms.
Das ist nicht nur Geschwindigkeit. Für Personalisierung brauchst du keinen Origin-Request mehr. User-Segmente, Präferenzen, Warenkorbstatus — alles im Edge-KV gespeichert. Wenn ein Request ankommt, liest die Edge-Function diese Daten und rendert HTML sofort. Der Origin-Server wird nur für Schreiboperationen und schwere Berechnungen genutzt.
Bei Plattformen wie Shopify ist diese Architektur besonders wertvoll. Liquid-Templates werden auf dem Origin gerendert und dauern pro Seite 300–600ms. Mit Edge SSR machst du HTML komposierbar: Eine Edge-Function rendert die Produktkarte, eine andere injiziert Warenkorbinformationen. Gesamtlatenz bleibt unter 40ms. Für tiefere Integrationsmuster siehe Headless Commerce.
Cloudflare Workers + KV: Der architektonische Kern
Cloudflare Workers läuft auf V8-Isolaten. Es startet keine neuen Container pro Request, sondern öffnet JavaScript-Isolate. Der Overhead: 0,5–2ms. Der Worker-Code sieht so aus:
export default {
async fetch(request, env) {
const url = new URL(request.url);
const userId = request.headers.get('CF-Connecting-IP') || 'anonymous';
// User-Segment aus KV auslesen
const segment = await env.USER_SEGMENTS.get(userId);
// Produktliste je nach Segment rendern
const products = segment === 'premium'
? await fetchPremiumProducts()
: await fetchStandardProducts();
const html = renderHTML(products, segment);
return new Response(html, {
headers: { 'Content-Type': 'text/html; charset=utf-8' }
});
}
};
Cloudflare KV repliziert über 300+ POPs. Read-Latenz liegt global durchschnittlich bei 12ms. Writes verbreiten sich mit „Eventual Consistency" in 60 Sekunden. Deshalb schreibst du in KV nur selten ändernde Daten: User-Vorlieben, Segment-Zuordnungen, Feature Flags. Schnell wechselnde Daten wie Produktpreise holst du aus der Origin-API und cachest sie am Edge (mit Cache API, 60s TTL).
Vercel Edge vs. Cloudflare Workers
Vercel Edge Functions nutzen dasselbe V8-Isolate-Modell, aber ein anderes Netzwerk. Cloudflare: 300+ POPs; Vercel: ~15 regionale Edge-Standorte. Latenz-Vergleich (europäischer User, US-Origin):
| Runtime | Cold Start | KV-Lesevorgang | Gesamt TTFB |
|---|---|---|---|
| Origin SSR | 150ms | N/A | 380ms |
| Vercel Edge | 8ms | 22ms | 45ms |
| Cloudflare Workers | 1ms | 11ms | 28ms |
Vorteil von Vercel: tiefe Integration mit dem Next.js-Ökosystem. Du schreibst in middleware.ts, pusht den Code in Produktion, und die Orchestrierung übernimmt Vercel. Bei Cloudflare brauchst du Wrangler CLI und manuelle KV-Bindungen. Tradeoff: mehr Kontrolle vs. schnelleres Onboarding.
KV-Store-Architektur: Write-Pattern und Revalidation
Die Eventual Consistency von Edge-KV ist eine Beschränkung. Ein User klickt einen Button, seine Präferenz ändert sich — diese Änderung verteilt sich in 60 Sekunden auf alle Edges. In der Zwischenzeit könnten verschiedene POPs verschiedene Werte lesen. Lösung: Nach dem Schreiben zur Origin redirecten oder Client-seitig optimistic update machen.
Beispiel-Flow:
- User klickt auf „Dunkler Modus"
- Client sendet POST
/api/preferenceszum Origin - Origin schreibt
user:123:theme = darkins KV - Origin ruft die Cloudflare API zur sofortigen Cache-Invalidierung auf:
// Auf dem Origin
await fetch(`https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${apiToken}` },
body: JSON.stringify({ files: [`https://example.com/user/${userId}`] })
});
- Die Edge-Function liest beim nächsten Request den neuen Wert aus KV
- Client-seitiges JavaScript führt nach 200ms ein Soft-Reload durch
Dieses Pattern beschränkt Write-Durchsatz (KV Write Rate Limit: 1000/Sekunde pro Konto), aber Read-Durchsatz ist unbegrenzt. Die Architektur ist also für Read-Heavy Workloads optimiert. User-Aktionen sind selten (1–2 pro Minute), Seitenaufrufe häufig (100+/Sekunde).
Cache-Layering-Strategie
KV ist nicht die einzige Cache-Ebene. Der Full Stack:
Browser-Cache (Service Worker)
↓
CDN-Edge-Cache (Cache API, 60s TTL)
↓
Edge KV (Eventual, Minuten)
↓
Origin-Datenbank
Static Assets (CSS, JS) oben, benutzerspezifische Daten unten. Das HTML selbst ist in der mittleren Schicht: die Edge-Function kombiniert KV + Cache API zum Rendern. Pseudocode:
const cacheKey = `html:${url}:${segment}`;
let html = await caches.default.match(cacheKey);
if (!html) {
const userData = await KV.get(userId);
html = renderTemplate(userData);
await caches.default.put(cacheKey, html, { expirationTtl: 60 });
}
return html;
Diese Struktur hält das 95th-Perzentil der TTFB unter 40ms, weil die meisten Requests aus der Cache API bedient werden (5–8ms). KV-Hit-Rate: 98%+, Origin-Fallback: <2%.
Personalisierungsumfang und Bundle-Size-Tradeoff
Edge Functions haben eine Bundle-Size-Grenze von 1MB (Cloudflare). Du kannst keine schweren React-Komponenten rendern. Zwei Strategien:
1. Minimales Templating: Handlebars oder Custom-String-Interpolation. Nur Variablen injizieren:
const template = `<div class="product-card">
<h3>{{name}}</h3>
<span class="price {{priceClass}}">{{price}}</span>
</div>`;
function render(product, segment) {
return template
.replace('{{name}}', product.name)
.replace('{{price}}', segment === 'premium' ? product.premiumPrice : product.price)
.replace('{{priceClass}}', segment === 'premium' ? 'gold' : 'standard');
}
Bundle-Größe: 2KB. Render-Zeit: 0,3ms.
2. Partial Hydration: Skeleton-HTML am Edge rendern, Client-seitig React-Islands hydratisieren. Edge-Function:
export default async function(request) {
const products = await fetchProducts();
return `
<div id="product-list" data-products='${JSON.stringify(products)}'>
${products.map(p => `<div class="skeleton"></div>`).join('')}
</div>
<script type="module" src="/hydrate.js"></script>
`;
}
Client-seitig hydrate.js (10KB):
import { h, render } from 'preact';
const data = JSON.parse(document.getElementById('product-list').dataset.products);
render(<ProductList products={data} />, document.getElementById('product-list'));
Mit diesem Pattern bleibt Edge-SSR-Latenz niedrig (40ms), Interaktivität kommt vom Client (FCP + 150ms). Tradeoff: INP könnte steigen (JavaScript-Parse-Zeit). Monitoring nötig.
Real User Monitoring und Alerting
Edge-Latenz ohne RUM zu optimieren ist unmöglich. Cloudflare Analytics fügt jedem Request einen Server-Timing-Header hinzu:
Server-Timing: cf-edge;dur=12, cf-kv;dur=8, cf-render;dur=18
Sammle das Client-seitig mit PerformanceObserver:
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'navigation') {
const ttfb = entry.responseStart - entry.requestStart;
fetch('/analytics', {
method: 'POST',
body: JSON.stringify({ ttfb, url: entry.name })
});
}
}
}).observe({ entryTypes: ['navigation'] });
Zielmetriken:
- p50 TTFB < 30ms
- p95 TTFB < 60ms
- p99 TTFB < 100ms
- Edge-Error-Rate < 0,1%
Überschreitet ein Request 60ms, logge die Cloudflare-Trace-ID und debugge mit wrangler tail. Meist sind Ursachen KV-Timeout oder Origin-Fallback.
Production-Deployment-Checkliste
Bevor Edge SSR in Produktion geht:
- Rate Limiting: Drossle KV-Writes (1 Write pro User/Sekunde)
- Fallback-Kette: Bei KV-Timeout (>50ms) fallback zum Origin, bei Origin-Timeout statische HTML zurückgeben
- Feature Flag: Edge-Personalisierung schrittweise aktivieren (10% → 50% → 100% Traffic)
- Cost-Monitoring: Cloudflare Workers 100K Requests/Tag kostenlos, dann $0,50/Million. KV-Reads kostenlos unbegrenzt, Writes $0,50/Million.
- Security: User-ID hashen, kein PII in KV-Keys, Bot-Detection für Rate-Limit-Bypass
Cost-Projektion: 1M tägliche Besuche, 30% personalisierte Requests = 300K Edge-Aufrufe/Tag = $0,15/Tag = $4,50/Monat. Origin-SSR-Alternative: 2-vCPU-Instance $50/Monat. Ersparnis: 91%.
Einmal eingerichtet, sind Edge-SSR-Kosten null-incremental. Eine neue Personalisierungsregel? Schreib einen neuen KV-Key. Ein neues Segment? Ein If-Block in der Edge-Function. Skalierung ist nicht linear, sondern logarithmisch — 10M Requests/Tag laufen genauso in unter 40ms. Deswegen ist Edge-First im Wachstumsstrategie ein grundlegender Vorteil.