aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webentwicklung

Next.js Data Fetching: fetch und Caching-Strategien

Next.js Data Fetching gehört zu den ersten Themen, die Entwickler nach dem Umstieg auf den App Router verwirren. Denn was das Verhalten deiner Seite bestimmt, ist nicht mehr nur, wo und wie du die Daten abrufst, sondern wann und wie lange diese Daten zwischengespeichert werden. Derselbe fetch-Aufruf kann eine Seite je nach den übergebenen Optionen vollständig statisch machen, bei jeder Anfrage neu erzeugen oder in festen Intervallen aktualisieren. In diesem Artikel erkläre ich die Unterschiede zwischen Static Rendering, SSR und ISR anhand konkreter Beispiele.

Die Grundlagen des Abrufs in Server Components

Im App Router sind Komponenten standardmäßig Server Components. Das bedeutet: Du kannst eine Komponente async machen und direkt darin await fetch(...) aufrufen. Kein separates useEffect, keine State-Verwaltung und kein Lade-Flag nötig; die Daten werden auf dem Server vorbereitet und in das an den Browser gesendete HTML eingebettet.

// app/produkte/page.tsx
export default async function ProduktePage() {
  const res = await fetch('https://api.beispiel.com/produkte');
  const produkte = await res.json();

  return (
    <ul>
      {produkte.map((p) => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  );
}

Entscheidend ist: Ob dieser Code statisch oder dynamisch läuft, hängt von den Optionen cache und next ab, die du an fetch übergibst.

Static Rendering: einmal bauen, endlos ausliefern

Static Rendering erzeugt die Seite einmal zur Build-Zeit und liefert das resultierende HTML immer wieder aus. Es eignet sich ideal für selten wechselnde Inhalte — Blogartikel, Dokumentation, Produktbeschreibungen — denn jede Anfrage wird so schnell wie eine CDN-Datei beantwortet.

Ein wichtiges Detail: Mit Next.js 15 hat sich das Standardverhalten von fetch geändert. Anfragen werden jetzt standardmäßig nicht mehr gecacht (in Next.js 14 war der Standard gecacht). Wenn du statisches, gecachtes Verhalten möchtest, musst du es ausdrücklich aktivieren:

// Ergebnis dauerhaft cachen -> statisch
const res = await fetch('https://api.beispiel.com/produkte', {
  cache: 'force-cache',
});

Bei Routen mit dynamischem Segment (z. B. app/blog/[slug]/page.tsx) gibst du mit generateStaticParams an, welche Seiten vorab erzeugt werden:

export async function generateStaticParams() {
  const beitraege = await fetch('https://api.beispiel.com/beitraege').then((r) => r.json());
  return beitraege.map((b) => ({ slug: b.slug }));
}

SSR: frische Daten bei jeder Anfrage

Server-Side Rendering (SSR) erzeugt die Seite bei jeder eingehenden Anfrage auf dem Server neu. Das ist die richtige Wahl für nutzerspezifische Dashboards, Warenkörbe, Live-Preise oder sich ständig ändernde Daten. Zum Aktivieren schaltest du den Cache vollständig ab:

const res = await fetch('https://api.beispiel.com/preise', {
  cache: 'no-store',
});

Denselben Effekt erreichst du auf Route-Segment-Ebene. Fügst du die folgende Zeile oben in die Seite ein, werden alle Daten dieser Route bei jeder Anfrage neu abgerufen:

export const dynamic = 'force-dynamic';

Die Route wechselt außerdem automatisch in den dynamischen Modus, sobald du cookies(), headers() oder searchParams liest, da die Ausgabe je nach Nutzer unterschiedlich sein kann.

ISR: statische Geschwindigkeit + periodische Aktualität

Incremental Static Regeneration (ISR) schlägt eine Brücke zwischen der Geschwindigkeit des Static Rendering und der Aktualität von SSR. Die Seite wird statisch ausgeliefert, aber sobald das von dir festgelegte Intervall abläuft, wird sie im Hintergrund neu erzeugt. Nutzer erhalten also stets eine schnelle gecachte Version, und der Inhalt aktualisiert sich mit einer angemessenen Verzögerung.

// Alle 60 Sekunden aktualisieren
const res = await fetch('https://api.beispiel.com/produkte', {
  next: { revalidate: 60 },
});

Du kannst dies auch auf Segmentebene definieren:

export const revalidate = 60;

ISR ist wie geschaffen für E-Commerce-Listen, Nachrichten-Feeds oder Dashboards, die sich ein paar Mal pro Stunde ändern: Selbst bei einer Million Anfragen pro Minute wird die Regeneration nur einmal ausgelöst, wenn das Intervall abläuft.

On-Demand-Revalidierung: Aktualisierung genau zum richtigen Zeitpunkt

Statt eines festen Intervalls möchtest du den Cache vielleicht leeren, wenn sich der Inhalt tatsächlich ändert. Next.js bietet dafür zwei Methoden: per Tag (revalidateTag) und per Pfad (revalidatePath). Zuerst markierst du den fetch mit einem Tag:

await fetch('https://api.beispiel.com/produkte', {
  next: { tags: ['produkte'] },
});

Anschließend machst du in einer Server Action oder einem Route Handler — etwa wenn ein Produkt im Adminbereich aktualisiert wird — diesen Tag ungültig:

import { revalidateTag } from 'next/cache';

revalidateTag('produkte');

So bleibt die Seite so schnell wie statisch und gibt Änderungen dennoch im Moment ihres Auftretens wieder. Für Projekte mit CMS oder Adminbereich bietet das eine weit feinere Kontrolle als zeitbasiertes ISR.

Die richtige Strategie wählen

  • Static: selten wechselnde Inhalte, höchste Performance. cache: 'force-cache'.
  • ISR: häufige Updates, die nicht sofort sein müssen. next: { revalidate: N }.
  • SSR: nutzerspezifische oder im Sekundentakt wechselnde Daten. cache: 'no-store'.
  • On-Demand: durch ein Ereignis ausgelöste Updates. tags + revalidateTag.

Ein praktischer Tipp: Beginne bei den meisten Seiten mit ISR und mach nicht alles force-dynamic, solange es nicht wirklich nötig ist. Unnötige Dynamik verschwendet den größten Vorteil, den dir Next.js bietet — den Cache.

Häufige Fragen

Warum unterscheidet sich das fetch-Caching zwischen Next.js 14 und 15?

In Next.js 15 wird fetch standardmäßig nicht gecacht; du aktivierst das Caching ausdrücklich mit cache: 'force-cache' oder revalidate. In Next.js 14 war es umgekehrt — der Standard war gecacht. Diesen Unterschied beim Upgrade älterer Projekte zu prüfen, vermeidet unerwartete Überraschungen.

Wie rufe ich Daten innerhalb einer Client Component ab?

Server-Caching greift in Client Components nicht; du rufst Daten auf die klassische Weise ab, etwa mit useEffect oder Bibliotheken wie SWR / React Query. Wann immer möglich ist es meist effizienter, die Daten in einer Server Component abzurufen und als Prop weiterzureichen.

Kann ich revalidate und force-dynamic zusammen verwenden?

Nein, beide stehen im Widerspruch. force-dynamic rendert die Seite bei jeder Anfrage und ignoriert den Cache, sodass das revalidate-Intervall bedeutungslos wird. Wähle revalidate für periodische Aktualisierung oder force-dynamic für volle Dynamik.

Möchtest du in deinem Next.js-Projekt eine Strategie für Datenabruf und Caching aufsetzen? Mit dem richtigen Render-Modell kann eine Website zugleich schnell und aktuell sein. Schauen wir es uns gemeinsam an: nimm Kontakt mit mir auf.

Bu kategorideki tüm yazılar →

Devamı için