Data Fetching
⏱ 15 min read read
Data Fetching in Server Components:
Server Components can be async --- you can await data directly in the
component body. No useEffect, no useState, no loading state needed.
// app/users/page.tsx --- Server Component
async function getUsers() {
const res = await fetch('https://api.example.com/users');
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
}
export default async function UsersPage() {
const users = await getUsers(); // ← just await it!
return (
<ul>
{users.map((u) => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Next.js fetch() Cache Options:
{ cache: 'force-cache' } ← cache forever (SSG behaviour, default)
{ cache: 'no-store' } ← never cache (SSR behaviour, always fresh)
{ next: { revalidate: 60 } } ← ISR: re-fetch every 60 seconds
{ next: { tags: ['posts'] } } ← on-demand revalidation by tag
Route Segment Config:
You can also set caching at the route level using exported constants:
// Force this entire page to be dynamic (SSR)
export const dynamic = 'force-dynamic';
// Or revalidate every hour
export const revalidate = 3600;
Parallel Data Fetching:
// Fetch both at the same time --- don't await one then the other
const [user, posts] = await Promise.all([
fetchUser(id),
fetchPosts(id),
]);
NEVER fetch data in useEffect for data that can be fetched on the
server.
useEffect fetching causes a waterfall: HTML → JS → fetch → render.
Server Component fetching: HTML arrives with data already included.
Use 'use client' + SWR/React Query only for client-side dynamic
data.
Server Components can be async --- you can await data directly in the
component body. No useEffect, no useState, no loading state needed.
// app/users/page.tsx --- Server Component
async function getUsers() {
const res = await fetch('https://api.example.com/users');
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
}
export default async function UsersPage() {
const users = await getUsers(); // ← just await it!
return (
<ul>
{users.map((u) => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Next.js fetch() Cache Options:
{ cache: 'force-cache' } ← cache forever (SSG behaviour, default)
{ cache: 'no-store' } ← never cache (SSR behaviour, always fresh)
{ next: { revalidate: 60 } } ← ISR: re-fetch every 60 seconds
{ next: { tags: ['posts'] } } ← on-demand revalidation by tag
Route Segment Config:
You can also set caching at the route level using exported constants:
// Force this entire page to be dynamic (SSR)
export const dynamic = 'force-dynamic';
// Or revalidate every hour
export const revalidate = 3600;
Parallel Data Fetching:
// Fetch both at the same time --- don't await one then the other
const [user, posts] = await Promise.all([
fetchUser(id),
fetchPosts(id),
]);
NEVER fetch data in useEffect for data that can be fetched on the
server.
useEffect fetching causes a waterfall: HTML → JS → fetch → render.
Server Component fetching: HTML arrives with data already included.
Use 'use client' + SWR/React Query only for client-side dynamic
data.
Log in to track your progress and earn badges as you complete lessons.
Log In to Track Progress