Suspense boundary

Each <Suspense> boundary emits its fallback immediately, then streams the resolved real content via an out-of-order <template> + __bextSuspense.swap(id) pair when the children settle. Open the network tab and watch the trickle — the fallbacks land in the first chunk, the real content lands as each promise resolves.

Tip
Importing <Suspense> from @bext-stack/framework/streaming automatically activates streaming mode for the route — no need to declare renderingMode manually. Each boundary is independent: a slow promise doesn't block the others.

Output (fallback first, real content swaps in)

  • loading fast…
  • loading medium…
  • loading slow…
src/app/examples/suspense/page.tsxTSX
import { Suspense } from "@bext-stack/framework/streaming";

async function slowQuery(label: string, ms: number) {
    await new Promise(r => setTimeout(r, ms));
    return <li>{label} ready ({ms}ms)</li>;
}
export default function Page() {
    return (
        <ul>
            <Suspense fallback={<li>loading fast…</li>}>{slowQuery("fast", 100)}</Suspense>
            <Suspense fallback={<li>loading med…</li>}>{slowQuery("med", 300)}</Suspense>
            <Suspense fallback={<li>loading slow…</li>}>{slowQuery("slow", 600)}</Suspense>
        </ul>
    );
}