Daten laden

Direkt in der Komponente

Server Components dürfen async sein und Daten direkt laden – ohne Umweg über eine eigene API-Route. Das ist einer der größten Gewinne des App Routers.

In der Server Component

export default async function Blog() {
    const res = await fetch('https://api.example.com/posts');
    const posts = await res.json();
    return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}

Genauso lässt sich direkt eine Datenbank oder ein ORM ansprechen – Zugangsdaten und Query-Logik landen dabei nie im Client-Bundle.

Caching: das hat sich geändert

Wichtig in aktuellem Next.js (15/16): fetch-Anfragen werden standardmäßig NICHT gecacht und blockieren, bis sie fertig sind. Identische Anfragen im selben Render werden aber dedupliziert (memoized).

Cachen bzw. revalidieren tut man bewusst:

// Ergebnis für eine Stunde zwischenspeichern (ISR)
export const revalidate = 3600;

// oder pro Anfrage:
await fetch(url, { next: { revalidate: 3600 } });

// immer frisch (dynamisch):
await fetch(url, { cache: 'no-store' });

In der Client Component

Client-Komponenten laden Daten anders – etwa über Bibliotheken wie SWR oder React Query, oder über die use-API, indem eine Server-Component ein Promise als Prop hereinreicht.

Praxis-Tipp: Lade Daten dort, wo du sie brauchst – dank Memoization musst du sie nicht umständlich durch den Baum reichen. Nur bei echten Abhängigkeiten (eine Anfrage braucht das Ergebnis der anderen) entsteht eine Kette; sonst starte parallel mit Promise.all.

Wie Next.js diese Seiten dann rendert – statisch, dynamisch oder gestreamt – klärt der nächste Punkt.