In the App Router you fetch data directly inside async Server Components using the standard fetch API — no getServerSideProps, no useEffect, no separate data layer. Next.js extends fetch with caching controls.
// app/posts/page.tsx — a Server Component
export default async function Posts() {
const res = await fetch("https://api.example.com/posts"); // runs on the server
const posts = await res.json();
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
Because the component runs on the server, you simply await your data and use it — far simpler than the client-side useEffect + useState + loading-state dance.
Next.js augments fetch so each call chooses its rendering behavior:
fetch(url, { cache: "force-cache" }); // SSG — cached (default for static)
fetch(url, { cache: "no-store" }); // SSR — fresh every request
fetch(url, { next: { revalidate: 60 } }); // ISR — revalidate every 60s
fetch(url, { next: { tags: ["posts"] } }); // tag for on-demand revalidation
This is the App Router's unified model: instead of choosing a page-level strategy, you control caching at the data-fetch level.
// ❌ sequential — each awaits the previous (slow waterfall)
const user = await getUser();
const posts = await getPosts();
// ✅ parallel — both start at once
const [user, posts] = await Promise.all([getUser(), getPosts()]);
Kick off independent requests together with Promise.all so they don't block each other.
"use client";
// for client-side data (e.g. after interaction), use a library like SWR or React Query
const { data } = useSWR("/api/user", fetcher);
Server Components cover most needs; use SWR/React Query for client-side, interactive, or frequently-revalidating data.
Next.js automatically dedupes identical fetch calls in a single render — so you can fetch the same data in a layout and a page without a double request.
Direct async data fetching in Server Components is one of the App Router's biggest simplifications — no boilerplate, secure server-side access, automatic deduping, and per-fetch caching that doubles as your SSG/SSR/ISR choice.
Knowing to parallelize independent fetches (avoiding waterfalls) is the key performance practice.