Start / Seminare / Next.js 16 Full-Stack-Entwicklung mit React und TypeScript

Modul

Caching mit Cache Components

7 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Caching mit Cache Components

0:00 Caching hat in Next.js einen schlechten Ruf, und der war eine Zeit lang verdient. Wer vor zwei Jahren gefragt hat, warum die Anwendung alte Daten zeigt, bekam selten eine befriedigende Antwort — weil das Caching unsichtbar war und an mehreren Stellen gleichzeitig passierte. Das hat sich grundlegend geändert, und ich halte die Änderung für eine der besseren der letzten Jahre.

0:21 Das neue Modell ist ausdrücklich: Nichts wird gecacht, was Sie nicht dazu erklären. In diesem Modul lernen Sie, wie Sie das tun, wie lange etwas leben soll und — der Teil, der am häufigsten schiefgeht — wie es wieder verschwindet.

Das Modell von Cache Components

0:35 Beginnen wir mit dem Grundprinzip, denn es unterscheidet sich fundamental von dem, was Sie vielleicht kennen. Der Unterschied lässt sich in einem Wort sagen: ausdrücklich. Was das im Alltag bedeutet, und warum es sich anfangs nach mehr Arbeit anfühlt und trotzdem eine Erleichterung ist, sehen wir uns jetzt an. Mit einem Schalter in der Konfiguration stellen Sie auf das heutige Modell um. Die Regel danach ist einfach: Nichts wird gecacht, was nicht ausdrücklich als cachebar markiert ist.

1:02 Kein unsichtbarer Zwischenspeicher, keine Vorgabe, die irgendwo greift. Das frühere Modell führt die Dokumentation nur noch als Vorgängermodell — sie hat es also nicht abgeschafft, aber deutlich zur Seite gestellt. Für Sie heißt das: Wenn Sie neu anfangen, fangen Sie hier an. Und wenn Sie ein bestehendes Projekt haben, wird die Umstellung ein eigener Arbeitsschritt sein.

1:25 Ein Schalter, mehr nicht — und trotzdem verändert diese Zeile das Verhalten Ihrer Anwendung erheblich. Worauf es ankommt: Ohne diesen Schalter gilt das alte Modell mit seinen impliziten Zwischenspeichern. Sie können das eine Weile parallel betreiben, sollten sich aber je Projekt entscheiden. Ein Hinweis für die Praxis: Wenn Sie ihn in einem gewachsenen Projekt umlegen, bekommen Sie anschließend eine ganze Reihe von Meldungen auf einmal.

1:50 Das ist kein Defekt, das ist die Bestandsaufnahme. Wir sprechen gleich darüber, wie man damit umgeht. Ich möchte kurz einordnen, warum ich diese Änderung für richtig halte. Die häufigste Frustration mit älterem Next.js war ein Satz: Warum sehe ich alte Daten? Und das Ärgerliche daran war nicht der Cache selbst, sondern dass er im Code nicht sichtbar war. Man suchte an einer Stelle, während die Ursache an einer anderen lag.

2:16 Jetzt steht im Code, was gecacht wird und wie lange. Wer nichts markiert, bekommt frische Daten — der sichere Ausgangszustand. Das ist mehr Schreibarbeit und weniger Rätselraten. Dieser Tausch lohnt sich. Der erste Punkt beschreibt die Kehrseite der Ausdrücklichkeit: Mit dem Schalter verlangt Next.js für jeden ungecachten Zugriff eine Suspense-Grenze.

2:37 Es lässt Sie also nicht mehr durchrutschen. Für ein neues Projekt ist das eine Führung, für ein bestehendes zunächst eine Wand aus Meldungen. Die gute Nachricht: Der Hersteller hat dafür einen eigenen Migrationsleitfaden und sogar eine fertige Anleitung für Coding-Agenten veröffentlicht, die das schrittweise durchgeht. Nehmen Sie sich die Zeit — jede dieser Meldungen zeigt eine Stelle, an der Ihre Anwendung heute langsamer ist als nötig.

Die Direktive use cache

3:02 Jetzt zum eigentlichen Werkzeug. Es ist eine einzige Zeile, und sie kann an zwei sehr unterschiedlichen Stellen stehen — mit entsprechend unterschiedlicher Wirkung. Diese beiden Ebenen auseinanderzuhalten ist der Schlüssel zu einer sinnvollen Cache-Strategie. Sehen wir uns beide an und klären, wann welche passt. Die Direktive steht am Anfang einer Funktion und cacht deren Rückgabewert. Steht sie am Anfang einer Komponente, cacht sie deren gerenderte Ausgabe.

3:29 Das ist der Unterschied zwischen Zutaten und fertigem Gericht — beides kann man aufbewahren, und es sind zwei verschiedene Entscheidungen. Ein wichtiges Detail: Argumente und Werte aus dem Umfeld werden Teil des Schlüssels. Rufen Sie dieselbe Funktion mit einer anderen Liegeplatznummer auf, bekommen Sie einen eigenen Eintrag.

3:47 Das ist gewollt und in den meisten Fällen genau richtig — es kann aber auch aus dem Ruder laufen. Was hier steht, ist unspektakulär, und genau das ist die Botschaft: Sie ergänzen zwei Zeilen in einer bestehenden Funktion. Kein Zusatzpaket, keine Konfiguration, kein eigener Cache-Dienst. Worauf es ankommt, ist die zweite Zeile — die Lebensdauer, über die wir gleich sprechen.

4:10 Und ein Hinweis, der überrascht: Steht die Direktive ganz oben in der Datei statt in der Funktion, gilt sie für alle Exporte dieser Datei. Das ist praktisch für einen Ordner mit lauter cachebaren Abfragen und gefährlich, wenn versehentlich eine benutzerbezogene dazwischenrutscht. Die Entscheidungsregel steckt in der Frage: Ist das Ergebnis unabhängig davon, wie es dargestellt wird? Dann cachen Sie die Daten. Ist die gesamte Darstellung für alle gleich?

4:37 Dann cachen Sie die Oberfläche. Die zweite Variante ist die mächtigere, weil sie auch die Renderarbeit spart. Unsere Hafenliste ist dafür ein gutes Beispiel — sie sieht für jeden Besucher gleich aus, warum sollte man sie also für jeden neu rendern? Sobald aber irgendetwas darin vom Betrachter abhängt, wechseln Sie auf die Datenebene oder verzichten ganz.

4:58 Der erste und zweite Punkt gehören zusammen und beschreiben, wie ein Cache explodiert. Alles, was in den Schlüssel eingeht, vervielfacht die Einträge — und in den Schlüssel geht mehr ein, als man denkt, nämlich auch Werte, die die Funktion aus ihrem Umfeld liest. Wenn dort versehentlich etwas Nutzerbezogenes steht, haben Sie plötzlich einen Eintrag je Nutzer. Das ist teuer und meistens nicht beabsichtigt.

5:22 Der dritte Punkt ist eine praktische Einschränkung: Nicht alles lässt sich speichern. Die Dokumentation nennt die Grenzen ausdrücklich, und ein Blick dorthin spart Zeit.

Lebensdauer mit cacheLife und cacheTag

5:32 Ein Cache ohne Verfallsdatum ist ein Datenleck in der Zeit. Deshalb geht es jetzt um zwei Ergänzungen, die zu jeder Cache-Direktive gehören: wie lange ein Eintrag gilt, und woran man ihn später wiederfindet, um ihn gezielt loszuwerden. Die Dokumentation ist bei der ersten davon ungewöhnlich deutlich — sie empfiehlt ausdrücklich, sie nie wegzulassen.

5:53 Die erste Ergänzung setzt eine Lebensdauer über benannte Profile — Stunden, Tage und so weiter. Die zweite hängt dem Eintrag einen Namen an, über den er später gezielt für ungültig erklärt werden kann. Denken Sie an ein Lager: Das Mindesthaltbarkeitsdatum ist das eine, das Etikett auf der Kiste das andere. Ohne Datum wissen Sie nicht, wann etwas raus muss.

6:14 Ohne Etikett finden Sie die Kiste nicht wieder, wenn Sie sie gezielt suchen. Beides zusammen macht aus einem Cache etwas Verwaltbares. Zwei Zeilen mehr als vorher, und beide haben einen konkreten Zweck. Die Lebensdauer bestimmt, wann der Eintrag von selbst erneuert wird. Der Tag ist der Griff, an dem gleich die Buchungsaktion ziehen wird. Worauf es ankommt: Setzen Sie den Tag jetzt, auch wenn Sie noch keine Aktion haben, die ihn braucht.

6:40 Ihn später nachzurüsten bedeutet, alle Stellen zu finden, an denen gecacht wird — und solange er fehlt, zeigt Ihre Anwendung nach jeder Änderung alte Daten, ohne dass irgendetwas fehlschlägt. Diese Tabelle beantwortet die Frage nicht technisch, sondern fachlich — und genau so sollten Sie sie stellen: Wie alt darf diese Information sein, ohne dass es jemandem schadet?

7:02 Bei der Tarifliste sind Stunden unproblematisch. Bei der Belegung wären Stunden ärgerlich, weil jemand einen Platz gebucht hätte, der noch als frei angezeigt wird. Und die letzte Zeile ist die wichtigste des ganzen Moduls: Persönliche Rechnungen werden gar nicht gecacht. Warum das nicht nur eine Frage der Aktualität ist, sondern eine der Sicherheit, sehen wir im nächsten Kapitel.

7:24 Der zweite Punkt ist der überraschendste: Eine zu kurze Lebensdauer schließt den Eintrag vom Vorabbauen aus. Das klingt widersinnig, ist aber logisch — was in wenigen Sekunden veraltet, lohnt sich nicht, in die vorgebaute Hülle zu schreiben. Sie können also durch übertriebene Vorsicht genau den Vorteil verlieren, den Sie erreichen wollten.

7:44 Der dritte Punkt ist eine stille Fehlerquelle: Ein Tag ohne passende Invalidierung ist wirkungslos. Er sieht im Code aus wie eine Vorsichtsmaßnahme und ist folgenlos. Wir kommen in Kapitel fünf darauf zurück.

Private und entfernte Caches

7:57 Jetzt zu einer Frage, die man beim Wort Cache selten stellt: Wo liegt das Zeug eigentlich? Die Antwort ist wichtiger, als sie klingt — sie entscheidet darüber, ob Ihr Cache auf Ihrer Plattform überhaupt etwas bringt, und im schlimmsten Fall darüber, ob ein Nutzer die Daten eines anderen sieht. Drei Speicherorte, drei verschiedene Eigenschaften.

8:16 Neben dem Standard gibt es zwei Varianten. Die private legt das Ergebnis ausschließlich im Browser des jeweiligen Nutzers ab — damit können Sie sogar Inhalte cachen, die Cookies lesen, weil sie niemand anderen erreichen. Die entfernte legt den Eintrag in einen dauerhaften, geteilten Speicher über Serverinstanzen hinweg. Denken Sie an drei Aufbewahrungsorte: die eigene Schreibtischschublade, das Schließfach des Nutzers und das gemeinsame Zentrallager.

8:42 Jeder hat seine Berechtigung, und jeder hat einen Preis. Die erste Zeile enthält die Überraschung, über die viele stolpern: Der Standard ist ein Speicher im laufenden Prozess — und der ist auf serverlosen Plattformen flüchtig. Ihr Cache-Eintrag überlebt dort unter Umständen keine zweite Anfrage, weil die schon auf einer anderen Instanz landet. Sie haben also gecacht und merken davon nichts.

9:05 Wenn Ihre Anwendung so betrieben wird und Sie echte Wiederverwendung brauchen, führt der Weg über den geteilten Speicher. Prüfen Sie das früh — es beeinflusst, ob sich der ganze Aufwand lohnt. Der geteilte Speicher klingt nach der besseren Wahl und ist es nicht immer. Er kostet einen Netzwerkweg bei jedem Zugriff. Wenn Ihre Trefferquote niedrig ist, zahlen Sie diesen Weg oft und sparen selten — dann ist der Cache langsamer als gar kein Cache.

9:30 Deshalb gehört diese Entscheidung in den Entwurf und nicht in ein späteres Optimierungsticket. Und noch etwas sollten Sie einplanen: Alle diese Speicher sind an eine Auslieferung gebunden. Nach jedem Deployment starten sie leer. Die erste Minute nach einem Rollout ist also immer die langsamste. Der zweite Punkt ist der sicherheitsrelevante und verdient Nachdruck: Der private Cache liegt im Browser. Für den Nutzer selbst ist er lesbar.

9:56 Alles, was dort hineingeht, muss also für diesen Nutzer bestimmt sein — was bei personalisierten Inhalten genau der Fall ist und der Grund für diese Variante. Aber legen Sie dort nichts ab, was Sie ihm nicht auch auf die Seite schreiben würden. Der dritte Punkt ist eine Betriebstatsache, die man kennen muss: Ein neuer Build macht alle Einträge ungültig, auch die dauerhaften.

Revalidieren mit updateTag und revalidateTag

10:17 Jetzt kommen wir zu dem Teil, der in der Praxis am häufigsten schiefgeht. Cachen ist einfach. Den Cache im richtigen Moment wieder loszuwerden, ist die eigentliche Aufgabe — und Fehler dabei fallen niemandem sofort auf, weil nichts abstürzt. Es werden nur alte Daten angezeigt. Sehen wir uns die Werkzeuge und den typischen Fehler an.

10:38 Nach einer Änderung müssen die betroffenen Einträge fallen. Dafür gibt es zwei Wege, die sich in der Dringlichkeit unterscheiden: Der eine markiert Einträge als veraltet, der andere erneuert sie unmittelbar. Dazu kommt eine Variante, die auf Pfadebene arbeitet. Und eine Regel gilt für alle: Aufgerufen wird das aus einer Aktion oder einem Endpunkt — also dort, wo etwas geändert wird.

11:01 Niemals während des Renderns. Next.js verhindert das sogar ausdrücklich, weil ein Seiteneffekt beim Darstellen genau die Art Fehler ist, die man nicht wiederfindet. Sehen Sie sich die letzte Zeile an — sie ist der Grund für dieses Kapitel. Ohne sie funktioniert alles: Die Buchung wird angelegt, die Aktion meldet Erfolg, der Nutzer sieht eine Bestätigung.

11:22 Nur zeigt die Belegungsübersicht danach den alten Stand, weil ihr Cache-Eintrag noch gilt. Der Nutzer bucht also einen Liegeplatz und sieht ihn anschließend weiterhin als frei. Worauf es ankommt: Diese Zeile gehört zur Änderung dazu, nicht als nachträgliche Optimierung. Machen Sie es sich zur Regel — wer schreibt, invalidiert.

11:42 Der Unterschied zwischen den ersten beiden Zeilen ist der Zeitpunkt: markieren oder sofort erneuern. Für die Belegung nach einer Buchung wollen Sie das Zweite, denn der Nutzer schaut jetzt hin. Die letzte Zeile ist die, die für Verwirrung sorgt — der Router-Auffrischer sieht aus wie eine Lösung und ist keine. Er aktualisiert die Ansicht im Browser, rührt aber die getaggten Daten nicht an. Wer nur ihn aufruft, wundert sich, warum dieselben alten Werte zurückkommen.

12:09 Beide Werkzeuge haben ihren Platz, und sie ersetzen einander nicht. Der dritte Punkt ist einer für den Betrieb und trifft erst mit der zweiten Instanz: Ein Tag wirkt zunächst nur auf der Instanz, auf der er gezogen wurde. Die anderen liefern weiter alte Daten aus, bis sie es selbst merken. Wenn Sie in einem Container-Umfeld betreiben, brauchen Sie dafür einen Cache-Handler, der diese Information verteilt.

12:33 Das ist genau die Art Problem, die lokal nie auftritt und in Produktion sporadisch aussieht — mal sind die Daten aktuell, mal nicht, je nachdem, welche Instanz antwortet. Wir kommen in Modul dreizehn darauf zurück.

Partial Prerendering verstehen

12:45 Jetzt fügt sich zusammen, was wir in den letzten beiden Modulen einzeln betrachtet haben. Aus dem Caching-Modell folgt nämlich, wie eine Seite gerendert wird — und das Ergebnis ist eine Mischung, die es so vorher nicht gab: eine einzige Seite, deren Teile zu drei verschiedenen Zeitpunkten entstehen. Dieses Verhalten ist heute der Standard.

13:05 Stellen Sie sich ein Schaufenster vor, das schon vollständig dekoriert ist, bevor der Laden öffnet — nur das Tagesangebot wird noch eingeschoben, wenn der erste Kunde kommt. Genau so entsteht Ihre Seite: Statisches und Gecachtes liegen fertig vor, die Platzhalter der Suspense-Grenzen liegen mit dabei, und der personalisierte Teil kommt zur Anfragezeit hinzu.

13:25 Der Nutzer bekommt sofort etwas Vollständiges zu sehen, das sich dann ergänzt. Das ist keine Einstellung, die man aktivieren muss — mit dem Caching-Modell ist es das Standardverhalten. Diese wenigen Zeilen zeigen alle drei Geschwindigkeiten nebeneinander. Die Kopfzeile ist statisch und liegt fertig vor. Die Tarifliste ist gecacht und liegt ebenfalls vor, wird aber regelmäßig erneuert. Die eigenen Buchungen hängen an der Sitzung und strömen nach.

13:51 Worauf es ankommt: Der Nutzer sieht keinen Unterschied zwischen den ersten beiden — für ihn ist die Seite einfach da. Und der dritte Teil erscheint dort, wo vorher ein Platzhalter war. Diese Mischung war früher nicht möglich; man musste sich je Seite entscheiden. Der erste Punkt ist der entscheidende: Die vorgebaute Hülle lässt sich direkt aus einem Auslieferungsnetz bedienen, ohne dass Ihr Server überhaupt gefragt wird.

14:16 Das ist der Unterschied zwischen zweihundert Millisekunden und zwanzig. Und weil das für jeden Direktaufruf gilt, wirkt die Anwendung sofort, nicht erst nach der Datenabfrage. Der personalisierte Teil kommt hinterher, ohne den Rest aufzuhalten. Genau diese Kombination bündelt Version 16.3 unter dem Namen Instant Navigations, und Sie sehen jetzt, dass das kein Marketingbegriff ist, sondern die Folge aus dem Caching-Modell.

14:40 Diese drei Punkte hängen zusammen und beschreiben eine Falle, auf die man von allein nicht kommt. Suchmaschinen und andere Maschinen bekommen keine Hülle mit nachströmendem Inhalt, sondern die vollständig gerenderte Seite — sie brauchen ein fertiges Dokument. Das bedeutet: Was beim Vorabbauen verfügbar war, muss auch zur Anfragezeit verfügbar sein.

15:00 Wenn Ihre Hülle sich auf etwas stützt, das es nur beim Bauen gibt, funktioniert die Seite für Menschen und scheitert für Crawler. Das ist der Sorte Fehler, die man erst bemerkt, wenn die Seite aus dem Index fällt.

Zufallswerte, Zeitstempel und connection

15:13 Zum Abschluss eine Gruppe von Fällen, die das Vorabbauen prinzipiell unmöglich machen — und bei denen Next.js Sie ausdrücklich zu einer Entscheidung zwingt. Es geht um Werte, die bei jedem Aufruf anders sind. Das klingt nach einem Randthema und begegnet Ihnen häufiger, als Sie denken. Zufallszahlen, die aktuelle Uhrzeit, erzeugte Kennungen — sie alle liefern bei jedem Lauf ein anderes Ergebnis.

15:36 Damit lässt sich nichts vorab bauen, denn was sollte man vorab bauen? Sie haben zwei Auswege, und beide sind legitim. Entweder Sie sagen ausdrücklich, dass dieser Teil zur Anfragezeit entstehen soll — dann bekommt jeder Nutzer seinen eigenen Wert. Oder Sie cachen ihn, dann teilen sich alle denselben. Was von beidem richtig ist, hängt daran, wofür Sie den Wert brauchen.

15:59 Der Aufruf am Anfang ist der interessante Teil: Er sagt dem Framework, dass hier ausdrücklich auf eine echte Anfrage gewartet werden soll. Danach darf die Komponente Werte erzeugen, die für jeden Aufruf verschieden sind. Worauf es ankommt: Ohne diesen Aufruf würde Next.js den Fall beanstanden, weil es die Komponente vorab bauen möchte und dabei einen Wert festschreiben würde, der eigentlich variabel sein soll.

16:22 Die Suspense-Grenze darum gehört dazu, sonst hält dieser kleine Teil wieder die ganze Seite auf. Der beruhigende Teil zuerst: Sie müssen sich das nicht merken. Die Entwicklungswerkzeuge melden jeden dieser Fälle und nennen gleich die passenden Lösungswege. Der zweite Punkt ist eine sinnvolle Ausnahme, die zeigt, wie sorgfältig hier gedacht wurde — Zeitmessungen für Telemetrie werden nicht beanstandet, weil sie nicht in der Ausgabe landen.

16:48 Und der dritte grenzt ab, was unproblematisch ist: Ein Import oder ein synchron gelesenes Konfigurationsfile liefert immer dasselbe. Solche Zugriffe laufen beim Vorabbauen mit, ganz ohne Zutun. In dieser Aufgabe treffen Sie für jede Datenquelle zwei Entscheidungen: Wie lange darf sie alt sein, und wie wird sie wieder frisch?

17:07 Der zweite Teil ist der, der in echten Projekten vergessen wird — deshalb steht er im Erfolgskriterium. Nach einer Buchung muss die Übersicht sofort den neuen Stand zeigen, nicht irgendwann. Wer schneller ist, öffnet den Navigations-Inspektor aus Modul drei und schaut nach, was tatsächlich in der Hülle liegt. Das ist der Moment, in dem die letzten beiden Module sichtbar zusammenkommen.

Modul 6 zusammengefasst

17:30 Vier Sätze zum Mitnehmen. Das Caching ist ausdrücklich — ungecacht ist der Ausgangszustand, und das ist gut so. Zu jeder Direktive gehören eine Lebensdauer und meistens ein Tag. Personenbezogene Daten gehören nie in einen geteilten Cache. Und Partial Prerendering mischt statisch, gecacht und strömend auf einer Seite — daher kommt die Geschwindigkeit.

17:51 Im nächsten Modul drehen wir die Richtung um: Bisher haben wir Daten gelesen, jetzt ändern wir sie. Und Sie werden sehen, dass die Cache-Tags von heute dort sofort wieder auftauchen.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →