SyntaxStudy
Sign Up
Next.js Fetching Data in Server Components
Next.js Beginner 1 min read

Fetching Data in Server Components

Next.js extends the native fetch Web API with additional caching and revalidation options. In Server Components you can call fetch() directly — Next.js automatically deduplicates identical fetch calls made during the same render pass, so multiple components requesting the same URL will only cause one network request. This makes it safe to fetch data close to where it is used rather than hoisting all fetches to a single parent. The cache option on fetch controls how the response is stored. fetch(url, { cache: 'force-cache' }) (the old default) stores the response indefinitely until manually invalidated. fetch(url, { cache: 'no-store' }) skips caching entirely, fetching fresh data on every request. fetch(url, { next: { revalidate: 60 } }) uses Incremental Static Regeneration semantics, returning cached data and regenerating the cache in the background after 60 seconds. When you need data from multiple independent sources, use Promise.all() to fetch them in parallel rather than sequentially. Sequential awaits inside a Server Component are a common performance mistake — each await blocks the next, so three 200 ms fetches become 600 ms instead of 200 ms. The React cache() function from 'react' can also memoize expensive function calls across a single render tree.
Example
// app/dashboard/page.tsx

// Parallel data fetching with Promise.all
async function getUserData(userId: string) {
  const res = await fetch(
    `https://api.example.com/users/${userId}`,
    { next: { revalidate: 300 } }, // cache for 5 minutes
  );
  if (!res.ok) throw new Error('Failed to fetch user');
  return res.json();
}

async function getUserPosts(userId: string) {
  const res = await fetch(
    `https://api.example.com/users/${userId}/posts`,
    { cache: 'no-store' }, // always fresh
  );
  if (!res.ok) throw new Error('Failed to fetch posts');
  return res.json();
}

export default async function DashboardPage({
  params,
}: {
  params: { userId: string };
}) {
  // Fetch in parallel — not sequential
  const [user, posts] = await Promise.all([
    getUserData(params.userId),
    getUserPosts(params.userId),
  ]);

  return (
    <div>
      <h1>Hello, {user.name}</h1>
      <ul>
        {posts.map((post: { id: string; title: string }) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}