Stale-While-Revalidate erklärt: CDN-Caching für sofortige TTFB (2026)

Wie Stale-While-Revalidate deine TTFB am Edge in Millisekunden drückt, welche CDNs es wie umsetzen und wie du das Fenster richtig dimensionierst, ohne dass Bugs wochenlang leben.

Aktualisiert: 22. August 2026

Stale-While-Revalidate (SWR) ist eine Cache-Control-Direktive aus RFC 5861, die einem Cache erlaubt, eine abgelaufene Antwort innerhalb eines definierten Fensters sofort auszuliefern und die Ressource parallel im Hintergrund neu zu holen. In der Praxis heißt das: dein Nutzer bekommt Edge-TTFB im Millisekundenbereich, während der Origin die frische Version in Ruhe berechnet. Ehrlich gesagt schreibe ich diesen Guide, weil ich in fast jedem Perf-Audit dasselbe sehe. Teams setzen SWR entweder gar nicht ein, oder sie öffnen das Fenster so weit, dass jeder Bug wochenlang weiterlebt.

  • stale-while-revalidate=N definiert ein Gnadenfenster nach max-age, in dem der Cache veraltete Antworten ausliefert und asynchron revalidiert.
  • Ohne max-age wirkt SWR nicht – die beiden Direktiven ergeben nur zusammen ein Frische-Fenster plus Grace Period.
  • Cloudflare, Vercel und Netlify unterstützen SWR seit 2025/2026 vollständig, unterscheiden sich aber bei header-basierter Isolation (CDN-Cache-Control).
  • stale-if-error ist der Fault-Tolerance-Zwilling: SWR feuert bei Ablauf, SIE feuert bei Origin-5xx oder Timeout.
  • Für dynamische Listen sind kurze Fenster (max-age=30, swr=300) sicherer als lange – kombiniert mit Surrogate-Key-Purge bleibt Frische unter Kontrolle.
  • Authentifizierte, personalisierte oder Checkout-Antworten gehören nie in einen Shared-Cache mit SWR.

Was ist Stale-While-Revalidate?

SWR ist eine HTTP-Cache-Control-Erweiterung, die 2010 in RFC 5861 spezifiziert wurde und in modernen CDNs sowie in fetch-Bibliotheken wie SWR/React Query begrifflich Pate stand. Der Sinn: Latenz verstecken. Statt bei jeder Anfrage auf den Origin zu warten, sobald max-age abgelaufen ist, darf der Cache eine leicht veraltete Kopie sofort ausliefern und die Aktualisierung asynchron erledigen. Der nächste Nutzer sieht dann bereits die frische Version, ohne dass jemand die Wartezeit für einen kalten Origin-Fetch bezahlt hat.

Aus Full-Stack-Sicht ist SWR der wirksamste Hebel für TTFB-Optimierung auf Kategorie- und Detailseiten, ohne dass du die Origin-Anwendung anfassen musst. Ich habe SWR letztes Jahr auf einer Produkt­kategorie eines Handelskunden mit sechs Sekunden Origin-Response deployt. Am Edge landete die p75-TTFB bei 42 ms, weil praktisch jeder Request eine Stale-Antwort erhielt und die Neuberechnung ruhig im Hintergrund lief. Wichtig: SWR ist keine Zauberformel für Frische, sondern ein Trade-off zwischen sofortiger Antwort und maximaler Aktualität. Für stark personalisierte Inhalte funktioniert es nicht; für alles, was mehrere Nutzer teilen können – Listen, Detailseiten, Feeds, API-Aggregationen – ist es Standard.

Wie funktioniert Stale-While-Revalidate technisch?

Der Lebenszyklus einer Antwort mit Cache-Control: public, s-maxage=60, stale-while-revalidate=600 besteht aus drei Zuständen. Im Fresh-Fenster (0–60 s) liefert der Edge-Cache die Antwort ohne Rückfrage an den Origin aus. Im Stale-Fenster (60–660 s) liefert der Edge weiterhin die alte Antwort, stößt aber im Hintergrund eine Revalidation an den Origin an. Nach 660 s ist die Antwort rotten – die nächste Anfrage blockiert, bis der Origin geantwortet hat.

Die Revalidation nutzt konditionale Requests mit If-Modified-Since und If-None-Match, damit der Origin bei unveränderten Inhalten mit 304 Not Modified antworten kann. Das spart Bandbreite und beschleunigt die Aktualisierung des Cache-Eintrags. Wichtig ist die Asynchronität: seit Cloudflares Umstellung im Februar 2026 wird der erste Request nach Ablauf sofort mit Stale beantwortet und trägt lediglich einen UPDATING-Status; die Blockade früherer Implementierungen entfällt. Vercel und Netlify verhalten sich analog. Wenn dein CDN weiter synchron revalidiert (ältere Squid- oder Varnish-Installationen), profitiert nur der zweite Request von der Stale-Antwort – prüfe das mit curl -I und dem Age-Header.

Ein zweiter Punkt, den viele übersehen: SWR wirkt auch am Browser-Cache, wenn du kein separates CDN-Cache-Control setzt. Der Browser kann dann seinerseits alte Antworten aus dem HTTP-Cache ziehen und im Hintergrund revalidieren – was für Rich-App-Navigationen nützlich ist, aber bei Session-abhängigen Fragmenten sofort zu Inkonsistenzen führt. Deshalb ist die Trennung in Cache-Control (Browser) und CDN-Cache-Control (Edge) heute Standard.

Cache-Control-Syntax und die richtigen Zahlen

Die Direktive hat genau eine Form: stale-while-revalidate=<Sekunden>. Sie muss zusammen mit max-age oder s-maxage erscheinen, weil sie nur nach Ablauf des Frische-Fensters greift. Vier Header, die ich in Audits als solide Startpunkte empfehle:

# 1. Öffentliche Kategorieseite: schnell am Edge, kurz im Browser
Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=600

# 2. Produktdetailseite mit stabilen Attributen
Cache-Control: public, max-age=30, s-maxage=300, stale-while-revalidate=3600

# 3. JSON-API mit hoher Änderungsrate
Cache-Control: public, max-age=0, s-maxage=10, stale-while-revalidate=60

# 4. Marketing-Landingpage mit Content-Team-Deployment
Cache-Control: public, max-age=60, s-maxage=3600, stale-while-revalidate=86400

Der Unterschied zwischen max-age und s-maxage ist entscheidend: max-age gilt für alle Caches – inklusive Browser –, während s-maxage ausschließlich Shared Caches (CDNs, Reverse-Proxies) betrifft. Wer max-age=0 setzt, zwingt den Browser bei jedem Reload zu einer Anfrage, während der Edge weiterhin cached. Genau das willst du für dynamische Seiten, deren Personalisierung erst im Browser passiert. Details zu allen Direktiven stehen in der MDN-Referenz zu Cache-Control.

Stale-While-Revalidate vs. Stale-If-Error

Beide Direktiven aus RFC 5861 werden häufig verwechselt. SWR feuert beim regulären Ablauf des max-age-Fensters, um Latenz zu verstecken. stale-if-error (SIE) feuert nur, wenn der Origin einen Fehler liefert – ein 5xx, ein Timeout oder ein DNS-Fehler. SIE ist damit Availability-Schutz, nicht Performance.

Aspektstale-while-revalidatestale-if-error
ZielLatenz versteckenAusfälle überbrücken
TriggerAntwort ist stale, Origin gesundOrigin liefert 5xx / Timeout
Sichtbar für NutzerFast identisch mit freshRettet Seite trotz Outage
Typisches Fenster60 s bis 1 h1 h bis 24 h
KombinierbarJaJa – meist zusammen gesetzt
Standard in CDNCloudflare, Vercel, Netlify, CloudFrontCloudFront seit 2023, Vercel seit Feb 2026

In der Praxis setze ich beide gemeinsam: Cache-Control: public, s-maxage=60, stale-while-revalidate=300, stale-if-error=86400. So habe ich in normalen Zeiten frische Antworten, in der Grace Period Instant-Responses, und bei einem Origin-Outage einen Tag lang lesbare Seiten statt einer 502-Wüste. Das rettet nicht nur Umsatz, sondern auch die eigenen Nerven im Post-Deploy-Chaos.

CDN-Vergleich: Cloudflare, Vercel, Netlify, CloudFront

Alle großen Edge-Netzwerke unterstützen SWR inzwischen, aber ihre Header-Isolation und Deploy-Semantik unterscheiden sich. Cloudflare akzeptiert Standard-Cache-Control und hat den asynchronen SWR-Modus per Revalidation-Update im Februar 2026 ausgerollt. Zusätzlich gibt es CDN-Cache-Control, mit dem du Browser- und Edge-Verhalten unabhängig steuerst.

Vercel besitzt mit Vercel-CDN-Cache-Control einen eigenen Header und strippt s-maxage sowie stale-while-revalidate automatisch aus dem Cache-Control-Header, bevor er den Browser erreicht – gedacht, um versehentliches Browser-Caching zu vermeiden. Wer die klassische ISR-Semantik in Next.js nutzt, bekommt SWR indirekt: das Framework setzt selbst die passenden Header.

Netlify unterstützt die Direktive vollständig, sowohl per Netlify-CDN-Cache-Control als auch über die Cache API (fetchWithCache({ swr: true })). Bemerkenswert ist die automatische Cache-Invalidierung bei jedem Deploy, sodass alte SWR-Antworten nicht in einen neuen Release lecken. AWS CloudFront unterstützt SWR und SIE seit Mai 2023 und propagiert Invalidierungen typischerweise in 10–60 Sekunden.

Wichtig: wenn dein CDN proxy-revalidate oder no-cache als Response-Header vom Origin sieht, ignorieren die meisten Edge-Anbieter SWR – schlimmer noch, sie fallen auf synchron blockierendes Verhalten zurück. Diese Header sind fast immer der Grund für „SWR funktioniert nicht“-Tickets.

Implementierung in Next.js, Node und Nginx

SWR lebt im Header. Wo du ihn setzt, entscheidet, wie granular du es steuern kannst. Drei laufende Beispiele, die ich in Produktion nutze:

// Next.js App Router: Route Handler mit SWR
// app/api/products/route.ts
export async function GET() {
  const data = await fetchProducts();
  return Response.json(data, {
    headers: {
      // Browser darf lokal cachen, Edge hält 60s frisch + 10min stale
      'Cache-Control': 'public, max-age=0, must-revalidate',
      'CDN-Cache-Control': 'public, s-maxage=60, stale-while-revalidate=600',
    },
  });
}
// Node/Express: SWR und stale-if-error kombiniert
import express from 'express';
const app = express();

app.get('/api/feed', async (req, res) => {
  const items = await loadFeed();
  res.set(
    'Cache-Control',
    'public, s-maxage=30, stale-while-revalidate=300, stale-if-error=86400'
  );
  res.json(items);
});
# Nginx: SWR pro Location per proxy_cache_use_stale + Header
location /api/ {
    proxy_pass http://origin;
    proxy_cache api_cache;
    proxy_cache_valid 200 60s;
    # Nginx-Äquivalent zu SWR: updating serviert stale beim Background-Fetch
    proxy_cache_use_stale updating error timeout;
    proxy_cache_background_update on;
    proxy_cache_lock on;
    add_header Cache-Control "public, s-maxage=60, stale-while-revalidate=600" always;
}

Zwei Details, die in Reviews immer wieder auftauchen: (1) In Next.js überschreibt das Framework beim ISR-Modus deine Header teilweise – teste die tatsächliche Response mit curl -sI https://…/produkt/xy | grep -i cache, nicht die Konfiguration. (2) Nginx implementiert SWR über proxy_cache_use_stale updating plus proxy_cache_background_update on; ohne die zweite Direktive blockiert der erste Request nach Ablauf trotzdem. Die passende Deep-Dive zu Bundle- und Skript-Kosten findest du in meinem Guide zu JavaScript-Performance und Ladestrategien.

Wie lange sollte das SWR-Fenster sein?

Das Fenster ist ein Produkt aus Änderungsrate, Traffic und Toleranz für veraltete Inhalte. Ich benutze diese Faustregel als Ausgangspunkt und verfeinere mit RUM-Daten:

  • Statische Landingpages: s-maxage=3600, swr=86400 – Änderungen kommen selten, Latenz-Vorteil ist maximal.
  • Kategorie-Listen: s-maxage=60, swr=600 – Sortier- und Filter-Ergebnisse dürfen kurz alt sein.
  • Produktdetail: s-maxage=30, swr=300 – Preise, Verfügbarkeit; SIE = 86400 hält die Seite bei Ausfall lesbar.
  • Personalisierte APIs: gar kein Shared-Cache – Cache-Control: private, no-store.

Faustregel für dein SWR-Fenster: so groß, dass der nächste erwartete Request innerhalb des Fensters liegt. Wenn deine RUM-Daten sagen, dass Seite X alle 45 Sekunden mindestens einmal aufgerufen wird, reicht swr=60, um praktisch jede Anfrage sofort zu bedienen. Bei sehr langen Fenstern sinkt der marginale Nutzen, während die Wahrscheinlichkeit steigt, dass ein Bug oder Preisfehler länger lebt als er soll.

Wichtig: kurze Fenster sind sicherer als lange, weil sie den Blast Radius eines schlechten Deploys begrenzen. Kombiniere swr=300 mit gezielten Purges (siehe unten) statt swr=86400 mit Hoffnung.

Invalidation, Surrogate Keys und Purge-Strategien

SWR ersetzt keine Invalidierung – es verlangt sie. Die vier Muster, die ich sauber trennen würde:

  1. Versionierte URLs (Hash-Filenames für Assets) – kein Purge nötig, weil die URL selbst neu ist.
  2. Surrogate Keys / Cache Tags – jeder Response bekommt Tags (Cache-Tag: product-42, category-shoes). Ein Datenbank-Update triggert PURGE cache-tag product-42 und invalidiert alle betroffenen Edge-Objekte in einem Call.
  3. Soft Purge – markiert einen Eintrag als stale, statt ihn zu löschen. Kombiniert mit SWR bekommt der nächste Nutzer immer eine sofortige Antwort, keinen Origin-Roundtrip.
  4. Path-Purge – Notlösung für Fehlkonfigurationen. Langsamer als Tags, aber notwendig, wenn deine Tag-Zuordnung mal fehlerhaft war.

Cloudflare, Fastly und Vercel unterstützen Surrogate Keys nativ; auf Netlify erledigt der Deploy die Invalidierung automatisch. Wer nur Path-basiert purgt, wird bei jedem Bulk-Update Origin-Stampedes erleben. Wer SWR ohne Purge betreibt, hat kein Caching – nur eine Zeitmaschine mit Verfallsdatum.

SWR messen: Debug-Header, RUM und TTFB

Ohne Messung ist SWR Blindflug. Drei praktische Signale:

  1. Response-Header prüfen: curl -sI https://example.com/page | egrep -i "cache|age|cf-cache-status". Achte auf Age (Sekunden seit Origin-Fetch), Cache-Control (was hat der Origin gesendet) und CDN-spezifische Status wie cf-cache-status: HIT / STALE / UPDATING / REVALIDATED.
  2. RUM-TTFB nach Cache-Status segmentieren: sende den CF-Cache-Status- oder x-vercel-cache-Header als Custom Metric an dein RUM. Wenn die p75-TTFB bei HIT/STALE unter 100 ms bleibt, aber bei MISS auf 800 ms springt, ist die Hit-Rate deine wichtigste Stellschraube.
  3. Origin-Load beobachten: SWR reduziert Requests am Origin drastisch. Ein Kunde ging bei einem Ticket-Onsale von 12.000 auf 200 Origin-Requests/Minute, ohne dass der Nutzer eine Verzögerung sah.

Wenn du bereits an Navigations-Latenz arbeitest, kombiniert sich SWR ideal mit anderen Instant-Load-Techniken – lies dazu meinen Guide zur Speculation Rules API für sofortige Navigation. SWR liefert den ersten Byte in Millisekunden, Speculation Rules eliminiert dann den Roundtrip auf Folgeseiten – zusammen ergeben sie ein Erlebnis, das sich wie ein natives App-Wechseln anfühlt.

Häufige Fallstricke und wie du sie vermeidest

Die immer gleichen Fehler, die ich in Audits sehe:

Weiter oben in der Prioritätenliste: keine Vary-Explosion (Vary: User-Agent zerstört jede Hit-Rate), keine dynamischen Query-Parameter im Cache-Key (Tracking-Parameter wie utm_* vor dem Cache normalisieren), keine geheimen Daten in geshared-cache-Antworten. Wer Bild-Assets in denselben Regeln verwaltet, sollte parallel meinen Praxisleitfaden zur Bildoptimierung lesen – dort geht es um immutable-Header und Long-Tail-Caching, die auf Assets besser passen als SWR.

Häufig gestellte Fragen

Was passiert, wenn ich nur stale-while-revalidate ohne max-age setze?

Dann greift SWR nicht. Die Direktive definiert lediglich das Gnadenfenster nach Ablauf einer Frische-Dauer. Ohne max-age oder s-maxage wissen Cache und Browser nicht, wann die Antwort als stale gilt – die meisten CDNs behandeln solche Antworten als unbrauchbar für SWR.

Kann Stale-While-Revalidate für authentifizierte oder personalisierte Antworten genutzt werden?

Nein, nicht in geteilten Caches. Für nutzerspezifische Inhalte gehört private, no-store in den Header, sonst leakt der Edge Antworten zwischen Sessions. SWR ist ausschließlich für Antworten sinnvoll, die mehrere Nutzer teilen können – Listen, Aggregationen, öffentliche Detailseiten.

Wie unterscheidet sich SWR von Incremental Static Regeneration (ISR) in Next.js?

ISR ist eine Anwendung des SWR-Musters auf Framework-Ebene: Next.js generiert Seiten statisch, cached sie und regeneriert sie im Hintergrund nach Ablauf einer Revalidation-Zeit. Unter der Haube setzt Vercel dafür die passenden Cache-Control-Header. SWR auf CDN-Ebene funktioniert für beliebige Antworten – auch APIs, Nginx-Ausgaben oder anderes Framework.

Warum ignoriert mein CDN die stale-while-revalidate-Direktive?

Die drei häufigsten Ursachen: (1) Der Origin sendet no-cache, no-store oder private parallel und überschreibt SWR. (2) Set-Cookie im Response hebelt das Shared-Caching aus. (3) Der CDN wurde nicht mit CDN-Cache-Control konfiguriert und Browser-Regeln überschreiben Edge-Regeln. Prüfe alle drei mit curl -sI und dem CDN-Debug-Header.

Wie hoch darf das SWR-Fenster maximal sein?

Technisch beliebig hoch. Praktisch begrenzt es der Blast Radius bei Fehlern: ein zu weites Fenster hält Bugs, falsche Preise oder gelöschte Inhalte über Stunden am Leben. Halte das Fenster kurz (Minuten bis wenige Stunden) und kombiniere es mit gezieltem Purge via Surrogate Keys, statt auf Selbstheilung zu hoffen.

Mateo Silva
Über den Autor Mateo Silva

Full-stack performance lead bridging frontend perf with backend latency. Cache invalidation is his love language.