13 — Data Fetching Patterns — Server-First, Parallel, Preload
The unintentional waterfall is the failure mode these patterns exist to prevent, and I've shipped it more than once. The model that clicked: fetch on the server by default, fetch only where necessary, and choose between parallel (start everything at once) and sequential (one fetch depends on the next) deliberately [1]. The unintentional waterfall is the failure mode these patterns exist to prevent.
The principles
The roadmap lays out the recommended patterns as a short list [1]:
- Fetch on the server. Server Components can fetch data directly, keeping the work off the client and closer to the data source.
- Fetch only where necessary. Push fetching down to the component that actually uses the data, rather than hoisting everything to a parent.
- Use streaming and Suspense to progressively render and stream units of the UI as data resolves.
- Choose parallel or sequential fetching based on whether the requests are independent or dependent.
- Preload data to start fetches early.
The first two are the worldview; the last three are the tactics.
Parallel vs sequential — the waterfall question
This is the central distinction. Sequential fetching means requests in a route depend on each other, creating a waterfall — A resolves, then B starts, then C [2]. Sometimes that's intentional: B genuinely needs A's result, or I want a condition satisfied before paying for the next fetch. Often it's accidental: a parent awaits its own fetch, then renders a child that awaits its own, serializing what could have been concurrent.
Parallel fetching means requests are initiated eagerly and load at the same time, reducing waterfalls and total load time [2]. For independent data, parallel is almost always correct.
The App Router helps here via Promise passthrough: a Server Component can start a fetch (returning a Promise) and pass that Promise to a child as a prop, rather than awaiting it in the parent. The child awaits the Promise; the parent doesn't block on it. This keeps independent fetches concurrent.
Preloading — starting fetches early
The preload pattern is the optimization on top of parallel fetching [3]. A preload function kicks off a fetch eagerly — before the component that needs the data even mounts — so the request is already in flight when the component renders. The roadmap frames it as a pattern, not an API: the function can have any name, and the payoff is hiding latency by overlapping fetch time with render time [3].
// a preload function — pattern, not API
import { getItem } from '@/lib/data';
export const preload = (id: string) => {
void getItem(id); // start the fetch eagerly, ignore the promise here
};
export default async function Page({ params }: { params: { id: string } }) {
preload(params.id); // kick off early
// …other work…
const item = await getItem(params.id); // already in flight, returns fast
return <ItemView item={item} />;
}The combined effect of parallel + preload: waterfalls collapse, total load time drops, and the user sees content sooner.
How I use this
My defaults: Server Components everywhere data is needed; fetch pushed down to the component that owns the data; independent fetches run in parallel (often via Promise passthrough rather than awaiting in the parent). I reach for sequential deliberately when a fetch genuinely depends on another's result. And for slow, predictable fetches, I add a preload to start them early. The discipline is to spot the accidental waterfall — a parent awaiting something a child could have started — and collapse it.
References
[1] Vercel, "Patterns and best practices," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/14/app/building-your-application/data-fetching/patterns#fetching-data-on-the-server
[2] Vercel, "Parallel and sequential data fetching," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/14/app/building-your-application/data-fetching/patterns#parallel-and-sequential-data-fetching
[3] Vercel, "Preloading data," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/14/app/building-your-application/data-fetching/patterns#preloading-data
[4] Vercel, "Fetching data," Next.js Docs, 2024. [Online]. Available: https://nextjs.org/docs/app/getting-started/fetching-data
Knowledge check · Question 1 of 4
What's the default recommendation for where to fetch data in Next.js App Router?
Comments
Leave a Comment
You must be signed in to comment
0 Comments
No comments yet. Be the first to comment!