Skip to content
Optimal Lab

Frontend · interactive

Data fetching without waterfalls

A profile page needs the user, then their posts, then the posts' comments, plus an unrelated sidebar. If each component fetches only after its parent has rendered, requests line up one behind another. Each request here is a 120 ms round trip plus 30 ms of work.

  • user190 ms
  • posts380 ms
  • comments570 ms
  • sidebar380 ms

page complete at 610 ms

The sidebar waits for the user even though it doesn't need it, and every step also waits for a render. Three round trips in a row, plus render gaps.

Strategy

Step 1 of 4

  1. 1

    Fetch-on-render makes waterfalls

    A child can't start fetching until its parent has loaded and rendered it.

    Spot them in the Network panel as staircases.

  2. 2

    Kick off independent requests together

    Hoist fetching to the route level and run unrelated requests in parallel.

    await Promise.all([getUser(), getSidebar()])

  3. 3

    Fetch on the server

    Server components and loaders query next to the database; dependent requests become cheap.

    Or one API endpoint shaped for the page.

  4. 4

    Cache and dedupe

    Libraries like TanStack Query share results between components and refetch smartly.

    Stream slow parts with Suspense.

In production

Tools and technologies

Data libraries and frameworks exist largely to avoid waterfalls.

Not tied to one language — use these names when you search docs or design a system.