Modernes Next.js Mapped: Was jede Funktion ersetzt und wann man sie verwenden sollte
Eine geführte Tour durch acht Funktionen von Next.js – von Server Components bis zur Metadata API –, die zeigt, welches alte Muster jede dieser Funktionen ersetzt und wo es zu Problemen kommen kann.
Next.js übernimmt nun die Routenverwaltung, das Datenabrufen, das Caching, die Render-Strategie sowie einen Großteil der API-Funktionalitäten. Dennoch beibehalten Teams oft alte Gewohnheiten: Das Abrufen von Daten in useEffect, manuell erstellte API-Endpunkte für jede Formularanfrage sowie Caching-Regeln, die niemand erklären kann. Dieser Leitfaden behandelt acht dieser Funktionen, das ältere Muster, das durch sie ersetzt wird, sowie die Probleme, die in echten Projekten auftreten, damit Sie Funktion für Funktion entscheiden können, was in Ihr Codebase gehört.
Warum das Framework nun die gesamte Stack-Struktur abdeckt
Unternehmen wie Walmart, Nike, TikTok, OpenAI und Airbnb nutzen Next.js für ihre Webanwendungen – der Vorteil liegt in der Konsolidierung: Routenverwaltung, Bündelung, Render-Modi, Datenzugriff und Server-Endpunkte teilen sich ein gemeinsames Repository sowie dieselben Konventionen. Die Auswahl eines Routeners und die Einrichtung eines Bündlers gehören nicht mehr zum Projektstart, wodurch mehr Zeit in die eigentliche Produktentwicklung fließen kann.
1. Server Components machen den Server zum Standardort für die Darstellung
React Server Components (RSC) stellen die größte architektonische Veränderung in dieser Liste dar. Ein Server Component wird ausschließlich auf dem Server ausgeführt und sendet die gerenderte Ausgabe an den Browser, sodass sein Code niemals Teil des clientseitigen JavaScript-Bundles wird.
Was verschwindet von einer datengetriebenen Seite
In klassischen, clientseitig gerenderten React-Anwendungen fügt selbst ein Komponente, das lediglich Daten liest und eine Liste anzeigt, seinen Code, seine Abruflogik sowie seine Abhängigkeiten zum Bundle hinzu, bevor es im Browser aktiviert wird. Mit RSC liest die Komponente die Daten auf dem Server und sendet nur das Ergebnis. Im App Router ist jede Komponente standardmäßig ein Server Component, es sei denn, man gibt etwas anderes an – deshalb benötigt die folgende Datei überhaupt keine Richtlinie:
// app/products/page.tsx
// This component runs ONLY on the server. No "use client" directive needed.
Die Seite ist eine async-Funktion, die direkt in die Datenbank abfragt und Markup zurückgibt. Es gibt weder eine API-Route dazwischen noch eine Anfrage auf der Client-Seite:
import { db } from "@/lib/db";export default async function ProductsPage() {
// Direct database access. No API route. No fetch boilerplate.
const products = await db.product.findMany({ take: 20 }); return (
<main>
<h1>Our Products</h1>
<ul>
{products.map((product) => (
<li key={product.id}>
<h2>{product.name}</h2>
<p>${product.price}</p>
</li>
))}
</ul>
</main>
);
}
Kein useState, kein useEffect, keine Ladeflagge, kein fetch zu einem eigenen Backend. Im Browser läuft weniger Code, das HTML kommt vollständig an (gut für Suchmaschinen), und es gibt weniger zu warten. Da dieser Code direkt die Datenbank berührt, sollte er niemals in eine Client-Datei importiert werden; ein ausschließlich serverseitiges Datenmodul macht diese Trennung klar.
Wo Client-Komponenten weiterhin hingehören
Für alles Interaktive benötigen Sie weiterhin Client-Komponenten: Event-Handler, Zustand, Effekte sowie Browser-APIs wie localStorage. Solche Dateien kennzeichnen Sie, indem Sie die Anweisung "use client" an den Anfang setzen:
// components/AddToCartButton.tsx
"use client";
Die untenstehende Schaltfläche speichert einen Teil des lokalen Zustands und reagiert auf Klicks – genau diese Art von Funktionalität muss im Browser ausgeführt werden:
import { useState } from "react";export function AddToCartButton({ productId }: { productId: string }) {
const [added, setAdded] = useState(false); return (
<button onClick={() => setAdded(true)}>
{added ? "Added!" : "Add to Cart"}
</button>
);
}
Beginnen Sie mit Server Components und wechseln Sie nur dort zu Client Components, wo Interaktivität erforderlich ist. Setzen Sie "use client" so tief wie möglich im Codebaum ein: Eine Serverseite, die nur eine kleine Client-Schaltfläche enthält, benötigt deutlich weniger JavaScript als eine Seite, die von Anfang an ein Client Component ist. Für einen tieferen Einblick in das Funktionsprinzip des Rendering-Modells siehe die Architektur hinter dem zero-bundle Rendering.
2. Server Actions ersetzen API-Endpunkte für Mutationen
Server Actions ermöglichen es Ihnen, eine Funktion zu schreiben, die auf dem Server ausgeführt wird, und sie direkt von einer Komponente aufzurufen. Next.js erzeugt den HTTP-Endpunkt, serialisiert die Argumente und gibt das Ergebnis zurück, sodass Sie keinen separaten Route mehr pflegen müssen, nur um eine Formulareingabe entgegenzunehmen.
Das von Server Actions abgelöste Zwei-Datei-Muster
Zuvor benötigte eine Mutation einen Handler im api-Ordner des Pages Routers, der den Anfragekörper las, in die Datenbank schrieb und mit JSON antwortete:
// You needed an API route
// pages/api/create-post.ts
export default async function handler(req, res) {
const { title, content } = req.body;
await db.post.create({ data: { title, content } });
res.status(200).json({ success: true });
}
Die Komponente musste anschließend diesen Endpunkt manuell aufrufen und den Payload selbst serialisieren:
// Then in your component:
const response = await fetch("/api/create-post", {
method: "POST",
body: JSON.stringify({ title, content }),
});
Eine validierte Aktion in derselben Datei wie das Formular
Mit Server Actions importiert die Seite, was sie benötigt – einschließlich Zod für die Eingabenvalidierung:
// app/posts/new/page.tsx
import { redirect } from "next/navigation";
import { db } from "@/lib/db";
import { z } from "zod";
Die Aktion wird neben dem Formular deklariert. Die Direktive "use server" innerhalb des Funktionskörpers kennzeichnet sie als serverseitigen Code; das Formular übermittelt sie an seine action-Eigenschaft. Die Aktion validiert FormData mit safeParse, gibt Feldfehler zurück, falls die Validierung fehlschlägt, und schreibt ansonsten den Inhalt ab sowie leitet um:
const schema = z.object({
title: z.string().min(3, "Title must be at least 3 characters"),
content: z.string().min(10, "Content is too short"),
});async function createPost(formData: FormData) {
"use server"; const parsed = schema.safeParse({
title: formData.get("title"),
content: formData.get("content"),
}); if (!parsed.success) {
return { error: parsed.error.flatten().fieldErrors };
} await db.post.create({ data: parsed.data });
redirect("/posts");
}export default function NewPostPage() {
return (
<form action={createPost}>
<input name="title" placeholder="Post title" required />
<textarea name="content" placeholder="Write something..." required />
<button type="submit">Publish</button>
</form>
);
}
Die Validierung ist unerlässlich, da eine Server Action ein öffentlicher Endpunkt ist, den jeder mit beliebigen Daten aufrufen kann. Aus demselben Grund müssen Autorisierungsprüfungen innerhalb der Aktion selbst erfolgen; warum Server Actions Autorisierungen innerhalb jedes Funktionskörpers benötigen erläutert dies ausführlich. Beachten Sie außerdem, dass hier nichts das zurückgegebene Fehlerobjekt liest, wodurch fehlgeschlagene Validierungen nicht sichtbar werden. Das folgende Muster behebt dieses Problem.
Fehler und Auslieferungszustand mit useActionState anzeigen
Falls das Formular Validierungsmitteilungen anzeigen oder die Schaltfläche während einer laufenden Anfrage deaktivieren muss, sollte das Formular in eine Client-Komponente verschoben und die Aktion mit Reacts useActionState-Hook umschlossen werden:
"use client";
Der Hook gibt den neuesten von der Aktion erzeugten Zustand, ein umschlossenes formAction, das an das Formular weitergegeben wird, sowie ein isPending-Flag zurück. Die Komponente zeigt den ersten Fehler pro Feld an und wechselt die Beschriftung der Schaltfläche während des Sendevorgangs aus:
import { useActionState } from "react";
import { createPost } from "./actions";export function PostForm() {
const [state, formAction, isPending] = useActionState(createPost, null); return (
<form action={formAction}>
<input name="title" placeholder="Post title" />
{state?.error?.title && (
<p className="text-red-500">{state.error.title[0]}</p>
)}
<textarea name="content" placeholder="Write something..." />
{state?.error?.content && (
<p className="text-red-500">{state.error.content[0]}</p>
)}
<button type="submit" disabled={isPending}>
{isPending ? "Publishing..." : "Publish"}
</button>
</form>
);
}
Ein Detail, das oft zu Verwirrung führt: Wenn eine Aktion über useActionState aufgerufen wird, übergibt React die vorherige Zustandsvariable als erstes Argument und das FormData als zweites. Die zuvor gezeigte Funktion createPost nimmt nur formData entgegen, weshalb eine aus ./actions exportierte Version für diesen Hook die Signatur (prevState, formData) benötigt. Zudem muss die Aktion in einer separaten Datei gespeichert sein, deren Anfang mit "use server" markiert ist – schließlich kann eine Client-Komponente Serverfunktionen nicht direkt einbinden.
3. Turbopack verkürzt den Entwicklungs-Feedback-Zyklus
Seit langer Zeit legte webpack den Ton für die lokale Entwicklung fest. Fast Refresh war angenehm, sobald der Server lief, doch bei großen Anwendungen konnten die Kaltstartzeiten 30 bis 60 Sekunden betragen. Turbopack ist ein auf Rust basierender Bundler von Vercel, der dazu entwickelt wurde, dieses Engpassproblem zu beseitigen.
Turbopack erreichte eine 100%-Passrate bei allen 8.298 Integrationstests für Next.js, und Teams berichten von Kaltstartzeiten unter 3 Sekunden bei Projekten, die früher länger als eine Minute benötigten. Sein Reifegrad wechselt bei den Updates schnell, daher sollten Sie die aktuellen Dokumente prüfen, um den Status in Ihrer Version zu erfahren – insbesondere hinsichtlich der Produktionsbauten.
Aktivierung
Die Aktivierung für die Entwicklung erfolgt über einen einzigen Flag im dev-Skript:
// package.json
{
"scripts": {
"dev": "next dev --turbopack",
"build": "next build"
}
}
Es ist keine zusätzliche Konfiguration erforderlich. Turbopack arbeitet schrittweise und rebuildet nur das, was sich geändert hat – dadurch profitieren besonders große Projekte am meisten. Falls Sie auf benutzerdefinierte webpack-Loader oder -Plugins angewiesen sind, überprüfen Sie zunächst die entsprechenden Turbopack-Äquivalente. Unsere Vergleichstabelle der Bundler geht auf diese Abwägungen ein.
4. Teilweises Vorkompilieren kombiniert eine statische Schale mit gestreamten Daten
Durch das Teilweise Vorkompilieren (PPR) wird sofort eine vorbereitete statische HTML-Schale bereitgestellt, wobei die dynamischen Teile derselben Seite innerhalb einer einzigen Antwort gestreamt werden.
Auf einer Produktseite sind Layout, Navigation und Beschreibung für alle Nutzer gleich; der personalisierte Preis, der Warenkorb sowie die Bestandsanzahl hingegen nicht. PPR sendet die Schale sofort und füllt die für jede Anfrage benötigten Elemente nach, sobald diese verfügbar sind.
Die Seite importiert ein statisches Komponente und zwei dynamische Komponenten:
// app/product/[id]/page.tsx
import { Suspense } from "react";
import { ProductDetails } from "./ProductDetails"; // static
import { PersonalizedPrice } from "./PersonalizedPrice"; // dynamic
import { StockStatus } from "./StockStatus"; // dynamic
Die Grenze zwischen statischen und dynamischen Komponenten wird mit Suspense definiert. Alles außerhalb dieser Grenze kann im Voraus gerendert werden; jeder Suspense-Fallback wird zu einem Platzhalter im Shell, der ersetzt wird, sobald seine Kinderkomponenten auf dem Server gerendert sind:
export default function ProductPage({ params }: { params: { id: string } }) {
return (
<div>
{/* This renders statically - instant */}
<ProductDetails id={params.id} /> {/* These stream in dynamically */}
<Suspense fallback={<div>Loading price...</div>}>
<PersonalizedPrice productId={params.id} />
</Suspense> <Suspense fallback={<div>Checking stock...</div>}>
<StockStatus productId={params.id} />
</Suspense>
</div>
);
}
Beachten Sie, dass params hier als einfaches Objekt typisiert ist. In neueren Next.js-Versionen wird params als Promise übergeben und muss abgewartet werden, daher müssen Sie die Signatur an die von Ihnen verwendete Version anpassen.
PPR wurde zunächst unter Verwendung eines experimentellen Flags in der Next.js-Konfiguration eingeführt, angefangen mit dem Typ-Import:
// next.config.ts
import type { NextConfig } from "next";
und anschließend mit dem Flag selbst:
const nextConfig: NextConfig = {
experimental: {
ppr: true,
},
};export default nextConfig;
Zum Zeitpunkt der Erstellung dieses Textes wurde diese Einstellung in neueren Versionen umorganisiert (das PPR-Verhalten hängt bei Next.js 16 von der Einstellung „Cache Components“ ab), daher sollten Sie den Auszug nur als Veranschaulichung betrachten und den aktuellen Namen der Option überprüfen. Auf jeden Fall wirkt die Seite statisch, da die Struktur im Cache gespeichert wird, während die Daten aktuell bleiben. Die dahinterstehenden Mechanismen werden ausführlicher in „Partial Pre-Rendering and Concurrent Rendering Explained“ behandelt.
5. Die Verwendung der cache-Direktive macht das Caching explizit
Next.js 13 und 14 cachten standardmäßig aggressiv, wodurch viele Teams in der Produktion veraltete Seiten ohne offensichtliche Ursache feststellten. Next.js 16 geht mit „Cache Components“ sowie der use cache-Direktive in Richtung eines optionalen Cachierens: Man markiert explizit, was gespeichert werden soll, anstatt zu raten, was bereits im Cache ist.
Wenn die Direktive an die Spitze eines asynchronen Komponenten gesetzt wird, wird deren renderter Ausgabe in Cache gebracht:
// A component that caches its output for 1 hour
async function PopularArticles() {
"use cache";
Der Rest der Komponente lädt und rendernt wie gewohnt:
const articles = await fetch("https://api.example.com/popular-articles").then(
(r) => r.json()
); return (
<ul>
{articles.map((article: { id: string; title: string }) => (
<li key={article.id}>{article.title}</li>
))}
</ul>
);
}
Der Kommentar erwähnt eine Stunde, doch die Direktive allein legt keine Dauer fest; die Lebensdauer ergibt sich aus einem Cache-Profil, das mit cacheLife angewendet wird, und fällt ansonsten auf ein Standardprofil zurück. Benutzerdefinierte Profile werden in der Konfiguration deklariert:
// next.config.ts
const nextConfig = {
experimental: {
cacheLife: {
"stale-for-a-day": {
stale: 60 * 60, // 1 hour
revalidate: 60 * 60 * 24, // 1 day
expire: 60 * 60 * 24 * 7, // 1 week
},
},
},
};
Die drei Werte beantworten unterschiedliche Fragen. stale gibt an, wie lange ein Client seine Kopie ohne Überprüfung beim Server verwenden darf, revalidate legt fest, wie oft der Server die Eintragung im Hintergrund aktualisiert, und expire ist der Zeitpunkt, nach dem die Eintragung verworfen wird und der nächste Anfrage auf frische Daten warten muss. Ob cacheLife unter experimental geführt wird, hängt von Ihrer Version ab. Für die auf Tags basierende Ungültigkeitsprüfung, die Sie benötigen, sobald Daten bei Schreibvorgängen geändert werden, siehe unsere Anleitung zur Verwendung von Cache und tagbasiertem Erneuern.
6. Streaming-Funktionen für KI mit dem AI SDK
Das Vercel AI SDK integriert sich in Route Handlers und React Hooks, sodass Streaming-Chat, KI-gestützte Suche sowie generierte Benutzeroberflächen zu gewöhnlichem Anwendungscode werden.
Auf dem Server importiert ein Route Handler streamText sowie einen Modellanbieter:
// app/api/chat/route.ts
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
Der POST-Handler liest das Gespräch aus dem Anfragekörper, startet eine Stream-Vollendung und gibt sie als gestreamte Antwort zurück (der schließende Klammernzeichen der Funktion ist im Auszug abgeschnitten):
export async function POST(req: Request) {
const { messages } = await req.json(); const result = streamText({
model: openai("gpt-4o"),
messages,
}); return result.toDataStreamResponse();
Auf der Client-Seite ist die Chat-Seite ein Client-Component, da sie den Eingabezustand speichert:
// app/chat/page.tsx
"use client";
Der Hook useChat verwaltet die Nachrichtenliste, den Eingabewert und die Übermittlung sowie lädt neu, sobald neue Tokens ankommen:
import { useChat } from "ai/react";export default function ChatPage() {
const { messages, input, handleInputChange, handleSubmit } = useChat(); return (
<div>
<div>
{messages.map((m) => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
</div>
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} placeholder="Ask anything..." />
<button type="submit">Send</button>
</form>
</div>
);
}
Das umfasst etwa 30 Zeilen für ein Streaming-Chat-System, wobei es einen Route Handler im Backend sowie useChat im Frontend gibt. Beachten Sie, dass die API des AI SDKs sich schnell entwickelt: In neueren Hauptversionen wird der Hook aus @ai-sdk/react importiert, der Eingabezustand muss von Ihnen verwaltet werden und der Response-Hilfsfunktion liegt ein anderer Name zugrunde. Pinnen Sie Ihre Versionen und prüfen Sie die SDK-Dokumentation, bevor Sie dies kopieren. Für agentbasierte Benutzeroberflächen mit Tools und mehreren Schritten siehe die Erstellung von mehrschrittigen AI-Agenten-Benutzeroberflächen mit Next.js und dem AI SDK.
7. Muster des App Router für komplexe Layouts
Der App Router, der in Next.js 13 eingeführt wurde, ist mittlerweile die Standardmethode zur Erstellung von Next.js-Apps. Zwei seiner Funktionen ersetzen das, was früher eine eigene Zustandsverwaltung erforderte.
Parallelwege für unabhängige Dashboard-Panelle
Parallelwege rendern mehrere Seiten gleichzeitig innerhalb eines Layouts. Jedes mit @ vorangestellte Verzeichnis definiert einen benannten Slot:
app/
dashboard/
@analytics/
page.tsx
@recent/
page.tsx
layout.tsx
page.tsx
Das Layout erhält jeden Slot als Eigenschaft zusammen mit children und platziert sie im Raster:
// app/dashboard/layout.tsx
export default function DashboardLayout({
children,
analytics,
recent,
}: {
children: React.ReactNode;
analytics: React.ReactNode;
recent: React.ReactNode;
}) {
return (
<div className="grid grid-cols-3 gap-4">
<div className="col-span-2">{children}</div>
<aside>
{analytics}
{recent}
</aside>
</div>
);
}
Weil jeder Slot ein eigenes Routensegment darstellt, lädt er seine eigenen Daten und kann eigene Lade- sowie Fehlerzustände haben. Eine langsame Analyseanfrage beeinträchtigt das Panel mit den neuesten Aktivitäten nicht. Ein Problem: Wenn man zu einem Unterpfad navigiert, den ein Slot nicht definiert, benötigt Next.js in diesem Slot eine Datei default.tsx, um bei einer erneuten Ladeung zu wissen, was angezeigt werden soll.
Routen abfangen für Modale mit echten URLs
Ein gängiges Interface-Muster öffnet ein Element in einem Modal-Fenster, während die URL auf dieses Element geändert wird, damit es geteilt werden kann. Die Routenabfangung kümmert sich dabei mit Ordnungsstruktur-Regeln darum:
app/
photos/
[id]/
page.tsx // Full page view at /photos/123
(..)[id]/
page.tsx // Intercepted modal view
page.tsx
Wenn ein Benutzer von der Gitteransicht aus klickt, fängt die abfangende Ordnung die Client-Seite-Navigation ab und zeigt die Modal-Version an. Wenn jemand die URL direkt aufruft oder neu lädt, wird stattdessen die normale Vollseitenansicht angezeigt – ohne manuelle Historie-Tricks. Die Marker (.), (..) und (...) beziehen sich auf Routensegmente, nicht auf Ordnernamen im Dateisystem. Das Modal-Fenster wird in der Regel über einen parallelen @modal-Slot angezeigt; prüfen Sie daher die Routing-Dokumentation, um das genaue Layout zu ermitteln, das Ihre Struktur benötigt.
8. SEO-Grundlagen: Metadaten und Bilder
Die Metadata API verwandelt SEO in gewöhnlichen Code, der neben der von ihm beschriebenen Seite liegt. Nach dem Import des Metadata-Typs:
// app/blog/[slug]/page.tsx
import type { Metadata } from "next";
exportiert eine Seite die Funktion generateMetadata, welche den Beitrag lädt und Titel, Beschreibung, Open Graph-Daten sowie Twitter-Card zurückgibt:
export async function generateMetadata({
params,
}: {
params: { slug: string };
}): Promise<Metadata> {
const post = await getPost(params.slug); return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{ url: post.coverImage }],
type: "article",
},
twitter: {
card: "summary_large_image",
title: post.title,
description: post.excerpt,
images: [post.coverImage],
},
};
}
Soziale Vorschauen, kanonische URLs und strukturierte Daten stammen aus denselben Daten, die von der Seite dargestellt werden. Wenn auch die Page-Komponente getPost aufruft, muss der Anfrage abgeglichen werden (zum Beispiel mit Reacts cache), damit die Datenbank nicht zweimal abgefragt wird.
Für Bilder sollte next/image die Standardlösung sein:
import Image from "next/image";
Durchgehend wird es standardmäßig verschoben geladen, es werden varianten mit der richtigen Größe bereitgestellt und es wird in WebP oder AVIF umgewandelt, sofern der Browser diese unterstützt. Explizite Angaben zu width und height reservieren außerdem Platz und verhindern Layout-Veränderungen:
export function ProductCard({ product }: { product: Product }) {
return (
<div>
<Image
src={product.imageUrl}
alt={product.name}
width={400}
height={300}
priority={false} // set true for above-the-fold images
/>
<h2>{product.name}</h2>
</div>
);
}
Setzen Sie priority nur auf true für das Bild, das oberhalb des Sichtbereichs sichtbar ist – in der Regel das Hero-Bild oder das Hauptproduktbild – damit der Browser es frühzeitig herunterlädt.
Eine sinnvolle Lernreihenfolge
Jeder Schritt baut auf dem vorherigen auf:
- Dateikonventionen im App Router:
layout.tsx,page.tsx,loading.tsxunderror.tsx. - Server Components sowie der Standort der Client-Grenze.
- Server Actions mit Zod-Validierung für jede Änderung.
- Suspense und Streaming zur deklarativen Darstellung von Ladezuständen.
Haupterkenntnisse
- Betrachten Sie den Server als Standard-Laufzeitumgebung und wenden Sie
"use client"auf die kleinsten interaktiven Komponenten an. - Server Actions sind Endpunkte: Validieren Sie die Eingaben und überprüfen Sie die Berechtigungen innerhalb jedes Endpunkts.
- Ziehen Sie Ihre statischen und dynamischen Grenzen mit
Suspense; sowohl PPR als auch Caching basieren darauf. - Ziehen Sie explizites Caching mit
use cacheund benanntencacheLife-Profilen der Verwendung von Standardwerten vor. - Viele dieser APIs haben sich in den letzten Versionen geändert, daher prüfen Sie Flags und Signaturen anhand der tatsächlich genutzten Version.
Egal, ob Sie von vorne anfangen oder eine große Anwendung auf den App Router migrieren – der schrittweise Einsatz dieser Elemente ist ein risikofreier Ansatz.
Verwandte Artikel
- 20 fortgeschrittene Next.js 16-Muster für die Anwendungsarchitektur auf Senior-Niveau — Eine Übersicht über serverbasiertes Design, Caching, Streaming, PPR, parallele und abfangende Routen sowie weitere Muster zur Erstellung skalierbarer Next.js 16-Anwendungen.
- Verständnis von Cache-Komponenten und teilweiser Vorausladeung in Next.js 16.3 — Erklärt, wie die Instant Navigations-Funktion in Next.js 16.3 gemeinsame Routenstrukturen sowie explizite Streaming-Entscheidungen nutzt, um serverseitig generierte Anwendungen sofortig erscheinen zu lassen.