Skip to content
</>CodeAndBuild

Next.js

Fetch data in the App Router without a waterfall

Colocate server fetches with the UI that renders them, and start independent requests together so a Next.js page does not wait on itself.

7 min read
  • Next.js
  • App Router
  • Data fetching
On this page
  1. Start independent work together
  2. Colocate the fetch with the component that renders it
  3. Prefer a Server Component over a route handler
  4. A short check before you ship

A Server Component can await a fetch directly. That is convenient, and it is also how a page grows a waterfall: the layout waits, then the page waits, then a child waits on a value the page already had.

Start independent work together

If two requests do not depend on each other, start them before you await either one. Promise.all keeps the slower request from stacking on top of the faster one.

app/page.tsxtsx
export default async function Page() {
  const guidesPromise = getGuides();
  const notesPromise = getNotes();
  const [guides, notes] = await Promise.all([
    guidesPromise,
    notesPromise,
  ]);

  return (
    <>
      <GuideList guides={guides} />
      <NoteList notes={notes} />
    </>
  );
}

Colocate the fetch with the component that renders it

Fetch in the component that renders the data so the dependency stays visible. Pass the result down only when a sibling needs the same value. Do not load the same record in a parent and again in a child.

Prefer a Server Component over a route handler

A route handler is an HTTP endpoint. Use one when a browser, a webhook, or another service must call your app. A page that only renders data for itself does not need that extra hop.

  • Use a Server Component for data that exists to render this page.
  • Use a route handler for clients that are not this React tree.
  • Use a Server Action when a form needs to change data and then refresh the page.

Read a slow page in this order

  1. The layout, which blocks every nested page.
  2. The page itself, which often refetches what the layout already loaded.
  3. Any child that cannot render until the page has finished.

A short check before you ship

  1. 01

    Name the requests

    If you cannot say what each promise returns, the page is doing too much.

  2. 02

    Mark the real dependency

    A request that needs an id from another request has to wait. Everything else can start immediately.

  3. 03

    Look at the sequence

    One slow request is a capacity problem. The same request stacked three times is a bug.

More guides