NAME
nextjs-16-cache-components — Next.js 16, Cache-Komponenten und React Compiler: Was sich wirklich ändert
SYNOPSIS
cat nextjs-16-cache-components.md
DESCRIPTION
Eine der nervigsten Fragen in Next.js lautet seit Jahren: „Ist diese Seite statisch oder dynamisch?“. Es scheint eine einfache Frage zu sein, bis Sie einen Aufruf zu cookies(), einem fetch mit verschiedenen Optionen, einem Datenbank-Client, einem CMS, einem Warenkorb oder einem benutzerdefinierten Inhalt hinzufügen.
Next.js 16 ist interessant, weil es versucht, diese Konversation weniger mysteriös zu gestalten. Dadurch wird die Komplexität nicht beseitigt, aber es verändert das mentale Modell: Routen sind standardmäßig dynamisch, der Cache deklariert sich dort, wo er benötigt wird, und Suspense wird zur natürlichen Möglichkeit, schnelle Shells mit Teilen zu erstellen, die frisch bleiben.
Die zu verstehende Funktion sind Cache-Komponenten. Stable Turbopack, React Compiler, proxy.ts und die neuen Invalidierungs-APIs sind wichtig, aber sie drehen sich um dasselbe Problem: schnelle Apps zu erstellen, ohne raten zu müssen, was das Framework hinter den Kulissen entschieden hat.
Weil diese Sache wichtig ist
In einer echten App gibt es nicht nur „statische Seiten“ und „dynamische Seiten“. Sie haben verschiedene Teile mit unterschiedlichen Bedürfnissen.
Das Produktblatt kann sich mehrmals täglich ändern. Der Preis kann sich öfter ändern. Die Verfügbarkeit muss nahezu live sein. Der Benutzername ist persönlich. Rezensionen können gestreamt werden. Die Seitenleiste kann stabil sein. Der Einkaufswagen funktioniert nicht.
Wenn man alles als eine Einheit betrachtet, landet man immer in einem von zwei Extremen:
- aggressives Caching und Risiko, alte Daten zu sehen;
- Überall dynamisches Rendering und schlechtere Leistung als nötig.
Cache Components dient genau dazu, diese falsche Wahl zu vermeiden.
Das Modell in der Praxis
Mit cacheComponents: true können Sie mit "use cache" deklarieren, was zwischenspeicherbar ist. Anschließend können Sie Dauer und Tags mit cacheLife() und cacheTag() verknüpfen. Dynamische Teile bleiben dynamisch und können mit Suspense isoliert werden.
Der Aufbau ist klein:
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { cacheComponents: true, }; export default nextConfig;
Die große Änderung liegt nicht in der Konfiguration. Es kommt darauf an, wie Sie mit dem Schreiben der Komponenten beginnen.
// app/products/[slug]/page.tsx import { Suspense } from 'react'; import { cacheLife, cacheTag } from 'next/cache'; async function getProduct(slug: string) { 'use cache'; cacheLife('hours'); cacheTag(`product:${slug}`); return db.product.findUnique({ where: { slug } }); } async function ProductDetails({ slug }: { slug: string }) { const product = await getProduct(slug); return ( <section> <h1>{product.name}</h1> <p>{product.description}</p> </section> ); } async function LiveInventory({ slug }: { slug: string }) { const inventory = await db.inventory.findFirst({ where: { slug } }); return <p>{inventory.quantity} pezzi disponibili</p>; } export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; return ( <> <ProductDetails slug={slug} /> <Suspense fallback={<p>Controllo disponibilità...</p>}> <LiveInventory slug={slug} /> </Suspense> </> ); }
Die Seite muss nicht vollständig zwischengespeichert oder vollständig dynamisch sein. Das Produktblatt kann schnell und wiederverwendbar sein. Der Bestand kann frisch bleiben. Der Benutzer sieht sofort etwas, ohne auf den langsamsten Teil warten zu müssen.
use cache ist eine ausführbare Dokumentation
Was mir an "use cache" gefällt, ist, dass es Sie dazu zwingt, eine Absicht deutlich zu machen. Wenn man eine Funktion liest, versteht man sofort, dass jemand entschieden hat: „Diese Daten können wiederverwendet werden“.
Dies ist besonders nützlich, wenn Sie fetch nicht verwenden. Viele Apps lesen Daten von Prisma, Drizzle, internen SDKs, CMS-Clients oder Servicefunktionen. In diesen Fällen reichte die alte Argumentation, die nur auf fetch-Optionen basierte, nicht aus.
Eine Faustregel:
- Cachea-Inhalt relativ stabil;
- Verwenden Sie granulare Tags.
- hinterlässt dynamische Berechtigungen, Sitzungen, Warenkörbe, Benachrichtigungen und Transaktionsstatus;
- langsame Teile in
Suspenseeinfügen; - messen, bevor wir sagen: „Wir haben die Leistung verbessert“.
Ungültig machen, ohne alles wegzuwerfen
Der Cache ist nur dann nützlich, wenn Sie ihn korrekt aktualisieren können. Hier werden cacheTag, revalidateTag und updateTag wichtig.
Beispiel:
'use server'; import { updateTag } from 'next/cache'; export async function updateProductName(productId: string, name: string) { await db.product.update({ where: { id: productId }, data: { name }, }); updateTag(`product:${productId}`); }
Das wichtige Detail ist das Etikett. product:${productId} gibt eine genaue Grenze an. products erzählt einen riesigen Eimer. Zunächst ist der riesige Eimer bequem; Nach ein paar Monaten wird es zum Grund, warum Sie eine halbe App ungültig machen, um einen Titel zu ändern.
Stabiler Turbopack: das Teil, das Sie jeden Tag hören
Next.js 16 bringt Turbopack ins Zentrum für Entwicklung und Build. Es ist nicht gerade das poetischste Feature, aber es ist das, was Sie bei der Arbeit spüren: Server, der früher startet, schnellere Aktualisierung, Builds, die sich nicht mehr wie eine erzwungene Kaffeepause anfühlen.
Allerdings würde ich eine Codebasis voller benutzerdefinierter Plugins nicht mit geschlossenen Augen migrieren. Ich würde prüfen:
- lokaler Build;
- Nicht-Standard-Import;
- MDX, SVG und CSS;
- Webpack-Plugins übrig;
- kritische Seiten;
- Unterschiede in den Bauzeiten.
Bei neuen Projekten würde ich mit der Standardeinstellung beginnen. Für ältere Menschen würde ich eine maßvolle Migration durchführen.
Compiler reagieren: Rauschen entfernen, nicht gedacht
React Compiler 1.0 ist stabil und Next.js 16 unterstützt ihn mit reactCompiler. Das Versprechen besteht darin, viele manuelle Auswendiglernen zu reduzieren: weniger memo, weniger useMemo, weniger useCallback, die „aus Sicherheitsgründen“ verwendet werden.
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { reactCompiler: true, }; export default nextConfig;
Ich würde es nicht wie einen magischen Staub behandeln. Der Compiler hilft, wenn der Code den React-Regeln gut folgt. Wenn Komponenten seltsame Nebenwirkungen, versteckte Mutationen oder falsch verwendete Hooks haben, muss das zuerst behoben werden.
Die gesunde Art, es auszuprobieren:
- aktualisieren
eslint-plugin-react-hooks; - tatsächliche Verstöße beheben;
- aktivieren Sie es in einem kontrollierten Bereich;
- Bauzeit und -verhalten messen;
- Entfernen Sie die manuelle Speicherung nur, wenn sie nicht mehr benötigt wird.
Das Ziel besteht nicht darin, jedes useMemo zu löschen. Das Ziel besteht darin, mit dem Schreiben präventiver Auswendiglernen aufzuhören, weil wir Angst vor dem Rendern haben.
proxy.ts und die Netzwerkgrenze
Das alte middleware.ts wird zu proxy.ts. Es handelt sich um eine Namensänderung, aber sie macht Sinn: Diese Datei befindet sich an der Anforderungsgrenze und ist keine herkömmliche generische Middleware im Backend-Stil.
// proxy.ts import { NextRequest, NextResponse } from 'next/server'; export default function proxy(request: NextRequest) { const isLoggedIn = Boolean(request.cookies.get('session')); if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); }
Die Regel hier ist einfach: Halten Sie es klein. Weiterleitung, Authentifizierungsrouting, Header, wesentliche Umschreibungen. Wenn es sich wie ein zweites Backend anfühlt, macht es wahrscheinlich zu viel.
Wie ich wirklich migrieren würde
Ich würde nicht alle Funktionen auf einmal aktivieren. Ich würde das tun:
- Ich aktualisiere Next, React und React DOM;
- Ich starte den offiziellen Codemod;
- Ich behebe Breaking Changes an
params,searchParams,cookies(),headers()unddraftMode(); - Ich migriere
middleware.tszuproxy.ts; - Ich überprüfe Builds und kritische Seiten.
- Ich aktiviere Cache-Komponenten in einem Abschnitt, in dem der Cache derzeit Reibung verursacht.
- Ich definiere Konventionen für Tags und Ungültigmachung;
- Ich versuche React Compiler separat;
- Vergleich der Kennzahlen vorher und nachher.
Die gute Migration ist nicht die, die alle neuen Funktionen nutzt. Dadurch wird das Verhalten der App besser lesbar.
Was ändert sich in der Denkweise?
Das Nützlichste an Next.js 16 ist, dass es Sie dazu zwingt, Absichten besser zu benennen. Eine Funktion ist nicht nur „das Produkt aus der Datenbank holen“. Es lautet: „Holen Sie sich das Produkt, ich kann es stundenlang zwischenspeichern, ich mache es mit diesem Tag ungültig.“ Eine Komponente ist nicht nur „die Seite rendern“. Es heißt: „Das ist die schnelle Hülle, dieses Stück ist persönlich, das kommt per Streaming.“
Auf den ersten Blick scheint es mehr Arbeit zu sein. Dann wird es eine Form der Ruhe. Leistungsentscheidungen sind nicht länger in einer Kombination aus Standardwerten, Heuristiken und Stammesgedächtnis verborgen. Sie stehen im Code.
Nützliche Quellen
METADATA
- date: 2026-05-24
- reading: 7 min
- author: Filippo Spinella
- tags: Next.js, React, Frontend, Performance