← All lessons
Lesson 07 · Intermediate

Data Fetching

Fetch directly inside server components using async/await. Pass data down through props.

In the App Router you fetch data right inside the component that needs it. Server components are async, so you can await your way through the request:

// app/blog/page.js
export default async function BlogPage() {
  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>
  );
}

No useEffect, no loading flag, no client-side waterfall. The page on the server resolves the data and then renders the HTML.

Parallel fetching

If two requests are independent, kick them off together with Promise.all so they overlap:

const [user, posts] = await Promise.all([
  fetch("/api/me").then((r) => r.json()),
  fetch("/api/posts").then((r) => r.json()),
]);

Sequential when you must

If request B depends on the result of A, run them in order:

const user = await fetch("/api/me").then((r) => r.json());
const profile = await fetch(`/api/profiles/${user.id}`).then((r) =>
  r.json()
);

Where to put fetches

  • Fetch in the component that displays the data. The framework de-duplicates identical requests within one render.
  • Pass data down to client components as props. Do not refetch the same thing in the browser.
  • If two distant components need the same data, just fetch in both — Next.js will cache and de-duplicate the request.

Caching at the fetch level

By default fetch in a server component is not cached across requests in Next.js 16 — you must opt in. Pass options on the fetch call:

// Cache forever until you redeploy:
await fetch(url, { cache: "force-cache" });

// Cache for 60 seconds, then refresh in the background:
await fetch(url, { next: { revalidate: 60 } });

// Tag the data so you can purge it later:
await fetch(url, { next: { tags: ["posts"] } });

Lesson 16 goes deep on caching and revalidation. For now: explicit options on each fetch, and no surprise caching.

Note: You do not have to use fetch — any data source works. A database client, an ORM, a file read. The key is that the call happens on the server.

Try it

Refactor this page to fetch both `user` and `tags` in parallel so the page is not slower than the slowest of the two requests.

Need a hint?

Use Promise.all when fetches don't depend on each other.

Quiz

Pick the best answer. You only get one shot per question.

1. Where should you call `fetch` in the App Router?

2. Two fetches in the same component don't depend on each other. What is the most efficient pattern?

3. You want to cache an API response for 60 seconds. What goes on the fetch call?