Suspense without waterfalls: where to put the boundaries
Suspense can stream a page piece by piece, but a misplaced boundary turns it into a queue at the post office. Three patterns that truly parallelize loading.
<Suspense> tells React: "while something inside is loading, show the fallback". Sounds simple, but where the boundary sits and when loading starts decide whether data is fetched in parallel or one request after another.
A waterfall in practice
async function Profile({ id }: { id: string }) {
const user = await getUser(id); // 300 ms
return (
<>
<h1>{user.name}</h1>
<Posts userId={id} /> {/* starts only after 300 ms */}
</>
);
}Posts starts rendering — and therefore fetching — only after Profile finishes its await. Two sequential waits = a waterfall.
Pattern 1: independent boundaries for independent data
export default function Page({ id }: { id: string }) {
return (
<>
<Suspense fallback={<HeaderSkeleton />}>
<ProfileHeader id={id} />
</Suspense>
<Suspense fallback={<PostsSkeleton />}>
<Posts userId={id} />
</Suspense>
</>
);
}Both components are siblings, so they start loading at the same time, and each appears as soon as it's ready.
Pattern 2: start fetching high, wait low
export default function Page({ id }: { id: string }) {
const userPromise = getUser(id); // starts now
const postsPromise = getPosts(id); // starts now
return (
<Suspense fallback={<Skeleton />}>
<Profile userPromise={userPromise} postsPromise={postsPromise} />
</Suspense>
);
}Inside, you await (Server Component) or use() (Client Component). The requests run in parallel even though they're read deep in the tree.
Pattern 3: group what belongs together
Not every component needs its own boundary. Five skeletons popping in random order feel worse than one that swaps out at once. Put a boundary where a visual unit makes sense — a card, a panel, a section.
Bonus: what changed in React 19
When a component suspends, React 19 commits the nearest fallback immediately and renders the siblings inside the same boundary afterwards ("pre-warming"). The fallback shows up sooner — which makes it even more important to start fetching higher in the tree (pattern 2) rather than in siblings waiting for their turn.