skip to content

How do you decide where to place <Suspense> boundaries across a React page, and what goes wrong at each extreme — one boundary around everything versus a boundary around every component?

level: principalimportance: should knowfreq 40%

answer

  1. a hole in the layout, not in the data
  2. match the box you replace
  3. one spinner or fifty
  4. optional content must never gate essential content
  5. decide update behaviour per region

basics

~20 s

Place a boundary where a placeholder can replace a region without moving anything around it, and where that region's data genuinely arrives at a different time from its neighbours. One boundary makes the whole page wait on its slowest part; a boundary per component produces a flickering mosaic that reflows repeatedly.

solid answer

~60 s

I treat boundary placement as a layout decision, not a data-fetching one. The two tests I apply are: does this region have a stable box, so a same-sized skeleton can stand in without shifting anything below it, and does it load on a genuinely different schedule from its neighbours? If both are yes, it earns a boundary. Content that always arrives together should share one boundary so it reveals together — that is the feature, not a limitation. The failure at one extreme is a single root boundary: any slow thing anywhere blanks the entire application, and the perceived load time becomes the slowest query on the page. The failure at the other extreme is a boundary per component: nothing waits for anything, but the user watches a field of placeholders resolve at random and the page reflows several times, which reads as broken even though every individual wait got shorter. I also decide, per region, whether an update should show the fallback at all or keep stale content behind a transition.

go deeper

for a junior

Know that where you put a <Suspense> boundary decides how much of the screen is replaced while loading, and that a placeholder should be about the same size as the content it stands in for.

for a middle

Be able to argue a placement: name the region, say what its fallback looks like, and explain why the neighbouring content should or should not wait for it. Recognise the single-root-boundary anti-pattern on sight.

for a senior

Show that you weigh perceived performance against visual stability — grouping content that should reveal together, keeping optional widgets from gating essential ones, and choosing per region whether updates flash a fallback or hold stale content.

for a principal

Own it as policy: who may declare a boundary, whether shared components carry their own, what the house skeleton vocabulary is, and how the team keeps loading behaviour consistent across pages instead of re-litigating it per feature.

## The question behind the question An interviewer asking this is not testing whether you know the `fallback` prop. They are testing whether you can reason about perceived performance and visual stability under uncertainty, because boundary placement has no single right answer — it depends on the shape of the page and on what the user is trying to do. ## Start from the layout, not the data The most useful reframe: a `<Suspense>` boundary is a **hole in the layout that can be filled by a placeholder**. So the first test is geometric. Draw the boundary around a region that occupies a predictable box — a card, a panel, a table body, a right-hand rail. A same-sized skeleton swaps into that box and nothing around it moves. Boundaries around content with unknown or content-driven height are where layout shift comes from. Whatever the placeholder's height, it is not the content's height, and everything below jumps when the real content lands. The mitigations are the ordinary ones — reserve a fixed height, use a skeleton that reproduces the real content's rows and spacing, place the boundary at a section that has its own scroll container — but the structural fix is choosing a different boundary. ## Then apply the data test The second test is independence. Two regions whose data always arrives at the same time gain nothing from separate boundaries: they will reveal at the same moment anyway, and you have paid for two skeleton designs and two more places for a mismatch to creep in. Two regions with materially different latency — a cheap header versus an expensive aggregation — do benefit, because the cheap one stops waiting on the expensive one. This is also where grouping becomes a deliberate act. If three cards belong to one visual row, putting them under a single boundary makes them appear together, which usually looks intentional; giving each its own boundary makes them pop in one at a time, which usually looks like a bug even though it is strictly faster. ## The failure at each extreme **One boundary at the root.** Every suspension anywhere in the app replaces the entire screen. Perceived load time collapses to the slowest thing on the page, and a slow widget in a corner is indistinguishable from a slow page. Worse, on updates the whole app blanks, so any re-suspend is maximally disruptive. This is the state most codebases start in, and pushing boundaries downward is the highest-value change available. **A boundary around every component.** Each individual wait is minimal, but the composite experience is worse: a mosaic of placeholders resolving in unpredictable order, several reflows as differently-sized content lands, and no moment where the page "arrives". There is also a real maintenance cost — every boundary is a fallback someone must design and keep in sync with the content it replaces. The right answer is almost always in the middle: a handful of boundaries aligned with the page's visual regions. ## Priority: what should the user see first Boundaries let you rank the page. Content the user came for should be outside a boundary if it can be, or inside the boundary that resolves first; peripheral content — recommendations, activity feeds, analytics widgets — belongs behind its own boundary so it never gates anything. A useful discipline is to ask what the minimum useful screen is, and make sure nothing optional can prevent it from rendering. ## Update behaviour is part of the placement decision For each boundary, decide what happens on an *update*, not just a first load. If the region's stale content is still meaningful, drive the update through a transition so the boundary keeps showing it instead of flashing back to the fallback. If stale content would mislead — a balance, a permission state, a different entity entirely — let the fallback show, and rely on tight placement so the fallback covers a panel rather than the page. ## Ownership and consistency At scale the interesting problem is not any single boundary but who is allowed to declare one. If shared components ship their own internal boundaries, page authors get sensible defaults but lose the ability to coarsen a reveal, and page-level fallbacks may never appear because a descendant boundary caught everything first. If only pages declare boundaries, the shared components are more composable but every page author re-solves the same problem. Either policy works; having no policy is what produces pages that each load in a visually different way. I would pair the policy with a small shared skeleton vocabulary, so placeholders across the product look like the same product. ## How I would answer in one breath Boundaries follow the layout; group content that arrives together; keep optional content from gating essential content; make the fallback the same shape as what it replaces; and decide per region whether updates show the fallback or hold stale content behind a transition.

  • Two dashboard cards always load from the same request. Do they get one boundary or two?
    One. They resolve at the same instant, so two boundaries buy nothing and cost an extra skeleton to design and maintain. A single boundary also makes them reveal together, which reads as intentional rather than as two independent things racing. Split them only if their data sources genuinely diverge later.
  • How do you keep boundary placement from causing layout shift when the content's height is unknown?
    Prefer boundaries at regions that already have a stable box, and give the placeholder the same box — fixed height, or a skeleton with the same number of rows and spacing as a typical result. Where height is genuinely unpredictable, put the region in its own scroll container or below the fold so a size change does not move content the user is reading.
  • How would you decide whether a shared component library should ship components with their own internal Suspense boundaries?
    By deciding who owns loading UI. Internal boundaries give consumers a correct, scoped fallback for free and stop one slow widget blanking a page, but they also swallow suspensions so a page-level fallback never sees them, and they hard-code a placeholder the page cannot coarsen. I would ship them for self-contained widgets, leave them out of layout primitives, and document which is which.

saying these in an interview costs you the question

  • Says more boundaries is always better because waits get shorter
  • Places boundaries by component tree shape rather than layout regions
  • Ignores that a differently sized fallback shifts everything below it
  • Puts one boundary at the root and treats the page as done
  • Never considers what the boundary does on updates, only first load

context