Next.js 15 Partial Prerendering: Praxismuster und Abwägungen
Next.js 15 Partial Prerendering (PPR) ist eine der bedeutendsten Änderungen an der Rendering-Architektur im React-Ökosystem seit Jahren. Das Versprechen ist überzeugend: einen statischen HTML-Shell sofort vom CDN-Edge ausliefern und dynamische Abschnitte streamen, sobald sie aufgelöst werden - alles aus einer einzigen Route, ohne Seiten manuell in separate statische und dynamische Segmente aufzuteilen. Teams, die PPR richtig einsetzen, erreichen Performance, die früher eine komplexe Micro-Frontend-Architektur erfordert hätte. Teams, die es falsch machen, liefern subtile, schwer reproduzierbare Fehler, die erst unter echtem Traffic auftreten.
Dieser Beitrag richtet sich an Entwickler und technische Leads, die Next.js 15 in der Produktion evaluieren oder bereits einsetzen. Er behandelt, was PPR auf der Rendering-Ebene tatsächlich tut, die Muster, die es zuverlässig machen, und die spezifischen Fehlermodi, die Teams kalt erwischen.
Was Next.js 15 Partial Prerendering wirklich tut
Im Kern teilt PPR eine einzelne Route in zwei Rendering-Ebenen auf. Der statische Shell - alles außerhalb einer <Suspense>-Boundary, das nicht von Request-Zeit-Daten abhängt - wird zu HTML vorgerendert und am Edge gecacht. Innerhalb von <Suspense>-Boundaries werden dynamische Komponenten zur Request-Zeit gestreamt.
Der entscheidende Unterschied zum Standard-App-Router-Streaming: Bei einer Nicht-PPR-Route veranlasst jeder dynamische Funktionsaufruf (cookies(), headers(), searchParams) innerhalb des Route-Baums Next.js dazu, die gesamte Route aus dem statischen Rendering auszuschließen. Mit aktiviertem PPR sind diese Aufrufe innerhalb von Suspense-Boundaries isoliert, sodass der äußere Shell weiterhin statisch gecacht werden kann, auch wenn eine untergeordnete Komponente ein Cookie liest.
Das bedeutet, dass der Cache-Key für den statischen Shell zur Build-Zeit bestimmt wird - und genau hier beginnt die Komplexität.
PPR in Next.js 15 aktivieren
PPR wurde in Next.js 15 von experimentell zu stabil befördert. Um es global zu aktivieren, füge Folgendes zu next.config.ts hinzu:
import type { NextConfig } from 'next'
const config: NextConfig = {
experimental: {
ppr: true,
},
}
export default config
Für inkrementelle Einführung auf bestimmten Routen exportiere experimental_ppr aus einer Layout- oder Page-Datei:
export const experimental_ppr = true
Das Pro-Route-Flag ist der sicherere Einstiegspunkt für bestehende Codebasen. Es ermöglicht die Migration stark frequentierter Seiten, ohne Routen mit komplexem dynamischen Verhalten zu berühren, die noch nicht vollständig geprüft wurden.
Muster 1: Das Static Shell / Dynamic Island Modell
Das zuverlässigste mentale Modell für PPR ist, die Seite als statischen Rahmen mit explizit markierten dynamischen Löchern zu behandeln. Navigation, Seitenheader, Marketing-Text und strukturelles Layout gehören in den statischen Shell. Nutzer-spezifische Inhalte, personalisierte Empfehlungen, Echtzeit-Zähler und alles hinter einer Auth-Schranke gehören in eine <Suspense>-Boundary mit einem aussagekräftigen Fallback.
// app/dashboard/page.tsx
export const experimental_ppr = true
export default function DashboardPage() {
return (
<div>
<StaticHero /> {/* vorgerendert, vom CDN ausgeliefert */}
<Suspense fallback={<MetricsSkeleton />}>
<LiveMetrics /> {/* zur Request-Zeit gestreamt */}
</Suspense>
<Suspense fallback={<FeedSkeleton />}>
<PersonalizedFeed /> {/* zur Request-Zeit gestreamt */}
</Suspense>
</div>
)
}
Die Fallback-Komponenten sind hier wichtiger als beim Standard-Streaming. Da der statische Shell gecacht und sofort ausgeliefert wird, sehen Nutzer das Skeleton sofort und beobachten dann, wie es durch echte Daten ersetzt wird. Ein schlechter Fallback - falsche Dimensionen, nicht passendes Layout - erzeugt einen störenden Layout-Shift, der sich oft schlimmer anfühlt als ein traditionelles Server-Rendering.
Muster 2: Auth isolieren ohne den Shell zu blockieren
Der häufigste PPR-Fehler ist das Lesen des Auth-Status im statischen Shell. Ein Aufruf von cookies() oder getServerSession() außerhalb einer Suspense-Boundary veranlasst Next.js, die gesamte Route auf dynamisches Rendering zurückzustufen - und überlastet PPR stillschweigend.
Der richtige Ansatz: Auth als dynamische Angelegenheit behandeln, die in einer Suspense-Boundary eingekapselt ist. Der statische Shell rendert den Seitenrahmen; auth-geschützte Inhalte rendern in einer Boundary, die gestreamt wird, sobald die Session aufgelöst ist.
async function AuthenticatedSection() {
const session = await getServerSession(authOptions)
if (!session) return <LoginPrompt />
return <UserDashboard user={session.user} />
}
export default function Page() {
return (
<>
<PublicPageHeader />
<Suspense fallback={<AuthSkeleton />}>
<AuthenticatedSection />
</Suspense>
</>
)
}
Dieses Muster hat einen weiteren Vorteil: Der öffentliche Shell kann gecacht und sowohl an nicht authentifizierte als auch an authentifizierte Nutzer ausgeliefert werden, was die CDN-Cache-Trefferrate erheblich verbessert.
Muster 3: Granulare statt breite Suspense-Boundaries
Teams, die vom Pages Router migrieren, wickeln häufig ganze Seitenabschnitte in eine einzige Suspense-Boundary als schnelle Lösung. Das funktioniert, verschwendet aber PPRs primären Vorteil: die Fähigkeit, unabhängige Datenquellen parallel zu streamen.
Bevorzuge schmale, zweckorientierte Boundaries statt breiter Wrapper. Wenn deine Sidebar von einer langsamen internen API abruft und dein Hauptinhalt aus einer schnellen Datenbank, zwingt eine einzige Boundary beide, auf die langsamere zu warten. Zwei Boundaries lassen den schnellen Abschnitt sofort rendern, während der langsame aufholt.
Das praktische Limit: Vermeide mehr als fünf oder sechs Suspense-Boundaries pro Route. Darüber hinaus beginnen Streaming-Overhead und Komplexität des Fallback-Managements die Parallelisierungsgewinne zu überwiegen.
Der Cache-Invalidierungsfehler, der die meisten Teams erwischt
Der subtilste PPR-Fehlermodus betrifft Build-Zeit-Daten, die dynamisch aussehen. Betrachte eine Navigationskomponente, die zur Render-Zeit ohne Caching-Direktive aus einem CMS abruft:
// Sieht sicher aus, ist aber eine Cache-Zeitbombe
async function Nav() {
const items = await fetch('https://cms.internal/nav').then(r => r.json())
return <Navigation items={items} />
}
Wenn Nav im statischen Shell ist (außerhalb von Suspense), wertet Next.js es zur Build-Zeit aus und backt das Ergebnis in das vorgerenderte HTML. Wenn sich CMS-Inhalte ändern, aktualisiert sich der statische Shell nicht bis zum nächsten Deployment - oder bis der Cache-TTL abläuft, falls Revalidierung in next.config.ts konfiguriert wurde.
Teams entdecken diesen Fehler, wenn ein CMS-Editor Navigationslinks aktualisiert und diese nicht auf der Live-Site erscheinen. Die Lösung ist entweder, die Komponente in eine Suspense-Boundary zu verschieben (sie dynamisch zu machen) oder explizite Revalidierung hinzuzufügen:
const items = await fetch('https://cms.internal/nav', {
next: { revalidate: 3600 }, // oder Tags für On-Demand-Revalidierung
}).then(r => r.json())
Diesen Unterschied zu verstehen - Build-Zeit-statisch versus Fetch-gecacht-statisch - ist das wichtigste mentale Modell für das Debugging von PPR in der Produktion.
Next.js 15 Caching-Änderungen, die PPR betreffen
Next.js 15 hat das Standard-Caching-Verhalten für fetch-Aufrufe in Server Components geändert: Antworten werden nicht mehr standardmäßig gecacht, anders als in Next.js 13 und 14. Diese Änderung ist besonders relevant für PPR, da dein statischer Shell Komponenten enthalten kann, die Fetch-Aufrufe machen, von denen du angenommen hast, dass sie aus einer früheren Codebasis gecacht werden.
Prüfe jeden fetch in deinem statischen Shell nach dem Upgrade. Füge explizite { cache: 'force-cache' } oder { next: { revalidate: N } } Optionen hinzu, wo du Caching möchtest, und verifiziere das Verhalten in den Next.js Dev Tools - das Request-Waterfall-Panel zeigt jetzt, ob ein Fetch den Cache oder das Netzwerk getroffen hat.
Wann PPR die Komplexität nicht wert ist
PPR fügt Architekturkomplexität hinzu, die nicht immer gerechtfertigt ist. Drei Szenarien, in denen du es überspringen solltest:
Vollständig authentifizierte Anwendungen. Wenn jede bedeutungsvolle Route eine Session erfordert, wird der statische Shell generisch genug sein, dass CDN-Caching minimalen Mehrwert bietet. Standard-Streaming mit loading.tsx-Dateien gibt dir den größten Teil des UX-Vorteils mit weit weniger Konfiguration.
Hochfrequente Daten mit strengen Frischeanforderungen. Wenn deine Schlüsselmetriken alle 30 Sekunden aktualisiert werden und Nutzer Live-Daten erwarten, ist die Streaming-Verzögerung aus einer dynamischen Boundary sichtbarer als die TTFB-Verbesserung durch den statischen Shell. Server-Sent Events oder WebSocket-Updates könnten besser passen - und die sorgfältige Auswahl des richtigen Anwendungsentwicklungs-Ansatzes ist hier entscheidend.
Teams, die neu beim App Router sind. PPR setzt Vertrautheit mit Datenabruf in Server Components, Suspense-Semantik und Next.js-Caching-Verhalten voraus. Es einzuführen, bevor das Team diese Grundlage hat, führt tendenziell zu inkonsistenten Ergebnissen und schwer zu diagnostizierenden Regressionen. Baut zuerst diese Grundlage, dann schichtet PPR darauf.
Praktische Migrations-Checkliste
Vor der PPR-Aktivierung auf einer bestehenden Route:
- Identifiziere alle dynamischen Funktionsaufrufe (
cookies,headers,useSearchParams) im Route-Baum und bestätige, dass sie sich in<Suspense>-Boundaries befinden. - Prüfe jeden
fetch-Aufruf im statischen Shell auf korrekte Caching-Direktiven. - Entwirf aussagekräftige Skeleton-Fallbacks, die den Dimensionen des endgültigen Inhalts entsprechen, um Layout-Shifts zu minimieren.
- Bestätige, dass Auth-Flows keinen Session-Status im statischen Shell lesen.
- Teste mit Netzwerk-Throttling, um zu bestätigen, dass der Fallback-zu-Inhalt-Übergang akzeptabel ist.
- Füge Monitoring für TTFB (sollte sich verbessern) und Streaming-Time-to-Content (sollte vergleichbar oder besser sein als zuvor) hinzu.
PPR in der breiteren App-Router-Architektur
Partial Prerendering ist keine eigenständige Funktion - es funktioniert am besten als Teil einer kohärenten App-Router-Architektur, die auch Route-Gruppierung, parallele Routen, abfangende Routen und die Server/Client-Component-Boundary berücksichtigt. Teams, die PPR als Drop-in-Performance-Fix behandeln ohne die breitere Architektur zu überprüfen, führen oft Inkonsistenzen ein, die als schwer reproduzierbare Rendering-Fehler unter Produktionslast auftauchen.
Das gilt besonders für B2B-SaaS-Produkte, bei denen bestimmte Nutzer Echtzeit-Dashboards benötigen und andere hauptsächlich statische Marketingseiten innerhalb derselben Next.js-Anwendung durchsuchen. Diese Aufteilung richtig hinzubekommen erfordert bewusste Architekturentscheidungen - nicht nur das Aktivieren eines Flags.
Wenn dein Team Next.js 15 einführt oder eine bestehende App-Router-Anwendung skaliert und ein Senior-Review der Rendering- und Datenabruf-Architektur möchte, bietet Wolf-Tech Code-Qualitäts-Consulting und individuelle Softwareentwicklung genau dafür. Wir arbeiten mit technischen Teams in Europa und Nordamerika an Next.js-, React- und Full-Stack-TypeScript-Anwendungen.
Kontaktiere uns unter hello@wolf-tech.io oder besuche wolf-tech.io, um deine Architektur zu besprechen.

