Caching verstehen
Warum die Seite nach dem Deploy plötzlich eingefroren ist
Next.js speichert an vier Stellen zwischen. Fast alle Überraschungen kommen daher, dass man nicht weiß, welche davon gerade zuschlägt.
Das ist die Lektion, an der die meisten hängenbleiben – und der Grund, warum Next.js den Ruf hat, „unvorhersehbar“ zu sein. Es ist aber vorhersehbar, sobald man die vier Speicher auseinanderhalten kann.
Im Entwicklungsmodus ist fast nichts zwischengespeichert. Wer Caching untersucht, muss npm run build && npm run start benutzen – sonst sieht man das Verhalten schlicht nicht.
Die vier Speicher
1. Request Memoization während EINES Seitenaufbaus
Derselbe fetch zweimal? Läuft trotzdem nur einmal.
2. Data Cache über Anfragen und Deploys hinweg
Antworten von fetch, bis du sie für ungültig erklärst.
3. Full Route Cache das fertige HTML statischer Seiten
Entsteht beim Bauen, wird danach direkt ausgeliefert.
4. Router Cache im Browser des Nutzers
Kürzlich besuchte Seiten, damit "zurück" sofort geht. Wie in einer Küche: Die Zutatenlieferung kommt nicht für jedes Gericht neu (Data CacheNext.js merkt sich Antworten von `fetch` über Anfragen und Deploys hinweg, bis du sie für ungültig erklärst.→). Ein Gericht, das immer gleich ist, wird vorgekocht (Full Route CacheDas fertig gerenderte HTML einer statischen Seite, das beim Bauen entsteht und danach direkt ausgeliefert wird.→). Und was der Gast eben schon auf dem Tisch hatte, muss nicht neu angerichtet werden (Router CacheDer Zwischenspeicher im Browser: Beim Zurücknavigieren zeigt Next.js die Seite sofort aus dem Speicher.→).
Der wichtigste: statisch oder dynamisch
Die größte Wirkung hat die Frage, ob eine Seite beim Bauen einmal entsteht (Statisches RendernDie Seite wird schon beim Bauen erzeugt und danach für alle gleich ausgeliefert. Schnell und billig – der Standard, wo möglich.→) oder bei jeder Anfrage neu (Dynamisches RendernDie Seite wird bei jeder Anfrage neu erzeugt. Nötig, sobald sie von Cookies, Kopfzeilen oder Suchparametern abhängt.→). Next.js entscheidet das selbst – anhand dessen, was du benutzt.
Statisch bleibt die Seite, solange du nichts davon anfasst.
Dynamisch wird sie, sobald du benutzt:
• cookies()
• headers()
• searchParams
• fetch(..., { cache: "no-store" })
• export const dynamic = "force-dynamic" Diese Dynamische Funktionen`cookies()`, `headers()` und `searchParams`. Sobald du eine benutzt, kann die Seite nicht mehr statisch sein.→ färben ab: Sobald irgendwo im Baum eine davon vorkommt, kann die ganze Seite nicht mehr statisch sein. Deshalb schiebt man sie so tief wie möglich – oder kapselt sie in ein <Suspense>, damit nur dieser Teil dynamisch wird.
Wie lange gelten geholte Daten?
// Standard: gespeichert, bis du es für ungültig erklärst
await fetch(url);
// Nie speichern – jede Anfrage holt frisch (macht die Seite dynamisch)
await fetch(url, { cache: "no-store" });
// Höchstens 60 Sekunden alt
await fetch(url, { next: { revalidate: 60 } });
// Mit Etikett, um es später gezielt für ungültig zu erklären
await fetch(url, { next: { tags: ["artikel"] } }); // Gilt für die ganze Seite statt pro fetch:
export const revalidate = 3600; // stündlich neu bauen
export const dynamic = "force-dynamic"; // immer frisch
export const dynamic = "force-static"; // immer statisch In frühen Versionen des App Routers war fetch immer zwischengespeichert, was viele überrascht hat. Seit Next.js 15 ist der Standard zurückhaltender. Wenn du einer älteren Anleitung folgst, prüfe die Version – dieser Punkt ist genau der, an dem sich alte und neue Beispiele widersprechen.
Was du wann brauchst
- +
Statisch: Marketingseiten, Blog, Dokumentation, Produktkatalog
- +
revalidate: Inhalte, die aktuell sein sollen, aber nicht sekundengenau - +
Dynamisch: alles Persönliche – Konto, Warenkorb, Dashboard
- −
no-storeals Reflex – damit verschenkst du den größten Vorteil - −
force-dynamicauf der ganzen Seite, obwohl nur ein Teil persönlich ist - −
Caching-Fragen im Entwicklungsmodus untersuchen
▸ Genauer erklärt: Fehlersuche bei Caching-Problemen optional
Wenn eine Seite falsche Daten zeigt, hilft diese Reihenfolge – von außen nach innen:
1. Ist die Seite überhaupt statisch?
npm run build zeigt es an:
○ statisch ← wird beim Bauen erzeugt
ƒ dynamisch ← bei jeder Anfrage
2. Zeigt ein harter Reload (Strg+Shift+R) frische Daten?
→ dann war es der Router Cache im Browser.
3. Zeigt ein neuer Build frische Daten?
→ dann war es der Full Route Cache: du brauchst revalidate.
4. Auch danach alt?
→ dann hängt es am Data Cache: revalidateTag oder no-store. npm run build listet jede Adresse mit einem Symbol davor. Wenn dort ein ○ steht, wo du ƒ erwartet hast, hast du die Ursache schon gefunden – ohne eine Zeile Code zu lesen.
Sitzt das schon?
5 Fragen zu dieser Lektion. Falsche Antworten landen in deiner Statistik.