Streaming + Suspense — Delivering Pages in Parts, Not All at Once
Streaming + Suspense — Delivering Pages in Parts, Not All at Once
💡 Why Should You Learn This? — The Slowest Fetch Blocks the Entire Page
Suspense Boundaries · loading.tsx · Progressive Streaming
1. How Suspense Boundaries Work
- ▸Header is sent as HTML immediately.
- ▸The slots for Reviews and Recommend are filled with their fallbacks.
- ▸Once each component's fetch completes, its HTML is streamed in-place (even after the closing
</html>tag).
2. loading.tsx — Automatic Suspense at the Folder Level
The fastest way to handle page-level loading states. No explicit import required.
3. Explicit vs. loading.tsx
In practice, use both together: loading.tsx for the overall skeleton, and
4. The Visual Effect of Progressive Streaming
User experience: 'Something loaded fast' (Header at 0.1s) → 'Reviews are in' (0.3s) → 'Recommendations too' (1s). With the old approach, users would see a blank screen for 1 second before everything appeared at once.
5. Avoiding Waterfall — Parallel Fetch + Parallel Suspense
6. Pairing with Error Boundaries — error.tsx
In the App Router, error.tsx automatically acts as an ErrorBoundary.
💡 💡 Streaming + Suspense: 5 Real-World Tips
1. loading.tsx covers the whole page;
If 90% of the page is waiting for data, loading.tsx is sufficient. If only a portion is slow, use
2. Only async Server Components are caught by Suspense
State data from a Client Component's useState is not caught by Suspense (that is the domain of useTransition / useDeferredValue).
3. An await inside Suspense automatically throws — React catches it
No need for explicit throw or try/catch. Just write an async function as-is.
4. Avoid waterfall — each component fetches its own data
If the parent fetches all data and passes it down via props, a waterfall occurs. When each component fetches its own data, React handles them in parallel.
5. Suspense boundaries pair with ErrorBoundary
If an await rejects, ErrorBoundary catches it — outside of Suspense, not inside. The App Router's error.tsx handles this automatically.