Suspense below shared layouts

Put the boundary under the layout both routes share.

Next.js docsMessage · blocking-prerender-dynamic
A single boundary in the root layout passes a page-load check but leaves sibling client navigations blocking.
Where to place the boundaryRead docs ↗

From next-cache-components-optimizer, patterns.md and SKILL.md.

Reload passes, click blocks

Click a tab, then compare with Reload.

Boundary in root layoutBad
app/layout.tsx wraps {children}
Boundary in store layoutGood
app/store/layout.tsx wraps {children}
// app/store/layout.tsx
import { Suspense } from 'react'

export default function StoreLayout({ children }: { children: React.ReactNode }) {
  return (
    <section>
      <StoreNav />
      <Suspense fallback={<Page.Skeleton />}>{children}</Suspense>
    </section>
  )
}
// or app/store/[slug]/loading.tsx: it covers both loads

Find the divergence point

Pick where the click starts and where it goes.

app/Soft navigation

    Why it matters, pros and cons

    Why it matters

    A click keeps shared layouts mounted and renders only the segments below them. A boundary above that point never shows.

    Pros

    • Clicks commit at once, with a skeleton.
    • The shared nav stays mounted and keeps its state.
    • A segment loading.tsx covers reloads and clicks.

    Cons

    • More boundaries, more fallbacks to keep in sync.
    • Reload tests won't catch it; test a real <Link> click.
    • Per-component boundaries in the page keep even more in the shell.