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.