When a React component suspends, which <Suspense> boundary shows its fallback, and how does nesting boundaries change how much of the screen is replaced?
answer
- nearest one wins
- like catch in a call stack
- boundaries do not stack their fallbacks
- nesting shrinks the blast radius
- outer reveals before inner waits
basics
~20 sThe nearest <Suspense> boundary above the suspended component shows its fallback; boundaries further up are unaffected. Nesting boundaries therefore shrinks the blast radius, letting an inner section swap to a small placeholder while everything outside it stays on screen.
solid answer
~50 sA suspension travels up the tree and is caught by the **nearest** enclosing `<Suspense>`, exactly one boundary — not every ancestor boundary. That boundary replaces its whole subtree with its `fallback`; ancestors above it, and sibling boundaries elsewhere, keep rendering normally. So the boundary you place is a declaration of blast radius: one boundary around the page means the whole page waits on the slowest thing in it, while a boundary around just the chart means only the chart's area turns into a skeleton. Nesting composes those radii — an outer boundary for the page shell, inner boundaries for independently loading regions. The one asymmetry worth saying out loud is that while an outer boundary is showing its fallback, the inner boundaries inside it are not mounted, so their fallbacks are irrelevant; inner placeholders only appear after the outer content has been revealed.
go deeper
Remember that only the closest <Suspense> above the loading component shows its fallback, and that the fallback replaces everything inside that boundary — not just the part that is loading.
Explain the capture rule and then use it: given a nested example, say exactly which fallback renders and what stays visible. Be able to state why adding an inner boundary reduces how much of the page disappears.
Demonstrate judgment about where boundaries belong — around layout boxes with stable dimensions, around regions with genuinely different latencies — and diagnose the two classic failures: a single root boundary that blanks everything, and a component library boundary that quietly swallows suspensions.
Own boundary placement as an architectural contract: which layer of the app is allowed to declare loading UI, whether shared components ship their own boundaries, and how the team keeps reveal behaviour consistent across pages rather than per-author.
## The capture rule When a component suspends, React walks up the tree from that component and stops at the first `<Suspense>` it finds. That one boundary switches to its `fallback`. Nothing else in the tree changes: ancestors above it keep their committed output, and a sibling boundary in a different part of the page is untouched. This is the same shape as `try`/`catch` in a call stack — the innermost handler wins, and handlers further out never see it. Getting this rule stated crisply is most of the question. ## Blast radius is the design knob Because exactly one boundary reacts, and it replaces its *entire* subtree, the placement of a boundary decides how much of the screen disappears: ```jsx <Suspense fallback={<PageSkeleton />}> <Sidebar /> <Suspense fallback={<ChartSkeleton />}> <RevenueChart /> </Suspense> </Suspense> ``` If `RevenueChart` is the only thing not ready, the inner boundary catches it: the user sees the sidebar plus a chart-sized skeleton. Delete the inner boundary and the same suspension is caught by the outer one — now the sidebar vanishes too and the whole page is a skeleton, even though the sidebar had nothing to wait for. That is the whole trade. Fewer boundaries mean coarser, more consistent reveals and less visual churn. More boundaries mean smaller waits, more of the page usable sooner, and a risk of the screen turning into a field of independently blinking placeholders. ## What nesting actually gives you Nesting is not additive — a suspension never shows two fallbacks. Nesting gives you *reveal granularity in stages*: 1. While the outer boundary is in fallback, its children are not on screen at all, so the inner boundary is not rendering and its fallback is irrelevant. 2. When the outer content is ready, React reveals it. If the inner region is still not ready, the inner boundary now shows its own fallback. The user therefore experiences the page filling in from the outside in: shell first, then regions. That ordering is a direct consequence of the capture rule, and it is the reason a page skeleton and a chart skeleton never appear at the same time. ## Choosing where the boundary goes A useful test: draw a boundary around content that can be replaced by a placeholder **without moving anything around it**. Regions that already have their own layout box — a card, a panel, a table body, a right-hand rail — are natural boundaries, because a same-sized skeleton swaps in without pushing neighbours around. Content that is inline with other text, or whose height is unknown, is a poor boundary: whatever placeholder you choose, the surrounding layout jumps when the real content lands. The second test is data independence. Two regions that always load together gain nothing from separate boundaries — they will reveal at the same moment anyway, and you have paid for two skeleton designs. Two regions with genuinely different latencies (a cached header versus an expensive aggregation) benefit, because the fast one no longer waits on the slow one. ## Common failure modes **One boundary at the root and nothing else.** Every suspension anywhere blanks the entire application. This is the most common real-world complaint and the fix is almost always to push boundaries down to the regions that actually wait. **A boundary around every component.** Now nothing waits for anything, but the first paint is a mosaic of placeholders that resolve at random times, and the page visibly reflows several times. Grouping related content under one boundary deliberately makes those pieces reveal together. **A boundary whose fallback is a different size than its content.** The boundary is correct, the placement is not: everything below it shifts when the content arrives. **Assuming an ancestor boundary also reacts.** It does not. If you want a coarser reveal, remove the inner boundary; adding one at the top does not override the inner one. ## The relationship to the rest of the tree Boundaries are ordinary components, so they compose like any other. A reusable panel component can ship with its own internal boundary, which means consumers get a sensibly scoped fallback for free — and it also means a consumer's outer boundary will never see suspensions originating inside that panel. That is usually what you want, but it is worth knowing when you are debugging why your page-level skeleton "never shows".
- If the outer and the inner boundary are both waiting, do both fallbacks appear?No. While the outer boundary is showing its fallback, its children are not rendered, so the inner boundary does not exist on screen and its fallback cannot appear. Only after the outer content is revealed does the inner boundary get a chance to show its own placeholder. The page fills in from the outside in.
- You want two regions to appear together rather than one at a time. How do you express that?Put them under a single boundary. A boundary is all-or-nothing, so grouping the two regions makes them wait for each other and reveal in the same commit. Splitting them into separate boundaries is the opposite instruction: reveal each as soon as it is individually ready.
- A reusable card component includes its own <Suspense> internally. What does that do to a page-level boundary above it?It shields it. Suspensions raised inside the card are caught by the card's own boundary, so the page-level fallback never sees them. That is usually desirable — the card degrades locally instead of blanking the page — but it explains the common confusion of a page skeleton that never appears no matter how slow the data is.
saying these in an interview costs you the question
- Thinks every ancestor boundary shows its fallback simultaneously
- Believes the outermost boundary catches the suspension
- Puts one boundary at the root and calls it done
- Expects nested fallbacks to render one inside the other
- Chooses boundaries by component tree shape rather than layout regions