Streaming UI with loading.tsx and Suspense Boundaries0%

Streaming UI with loading.tsx and Suspense Boundaries

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Streaming UI with loading.tsx and Suspense Boundaries

In traditional SSR architectures, the server must fetch all data for every component on the page before sending a single byte of HTML to the browser. If one slow database query takes 3 seconds, the user stares at a blank white screen for 3 seconds. Next.js 15 solves this completely with Streaming Server-Side Rendering and React Suspense.


1. How Streaming Works

Streaming allows the server to break down the page's HTML into smaller chunks and stream them progressively over the network as they become ready:

Output
1. Immediate: Server streams initial shell (Navbar, Layout, Skeletons)
2. 50ms later: Fast component (User Profile) streams in
3. 800ms later: Slow component (Course Analytics) streams in and replaces skeleton!

2. Instant Loading UI with loading.tsx

Creating a loading.tsx file inside any route segment automatically wraps that segment and its children in a <React.Suspense> boundary behind the scenes:

TSX
// app/courses/loading.tsx
export default function Loading() {
return (
<div className="max-w-6xl mx-auto p-6 space-y-6 animate-pulse">
<div className="h-8 bg-slate-200 rounded w-1/4"></div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[1, 2, 3, 4, 5, 6].map((i) => (
<div key={i} className="h-64 bg-slate-200 rounded-xl"></div>
))}
</div>
</div>
);
}

The user sees this skeleton UI instantly while the server processes the database query in page.tsx!


3. Granular Streaming with <Suspense> Boundaries

Instead of blocking the entire page with a single route-level loading.tsx, you can stream independent components with their own <Suspense> fallbacks:

TSX
// app/dashboard/page.tsx
import { Suspense } from 'react';
import UserProfileCard from '@/components/UserProfileCard'; // Fast component
import HeavyAnalyticsFeed from '@/components/HeavyAnalyticsFeed'; // Slow 2-second query
import CardSkeleton from '@/components/skeletons/CardSkeleton';
 
export default function DashboardPage() {
return (
<div className="p-8 space-y-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
 
{/* Fast component renders immediately */}
<UserProfileCard />
 
{/* Slow component streams in progressively without blocking the rest of the UI! */}
<Suspense fallback={<CardSkeleton title="Loading Analytics..." />}>
<HeavyAnalyticsFeed />
</Suspense>
</div>
);
}

Interactive Quiz

Multiple Choice Questions

Question 1
What problem does Streaming SSR solve compared to traditional monolithic Server-Side Rendering?
Question 2
Under the hood, what React primitive is automatically wrapped around page.tsx when a loading.tsx file is present in the same folder?
Question 3
What happens to the skeleton fallback UI when the streaming asynchronous component finishes data fetching?
Question 4
Why is streaming beneficial for First Contentful Paint (FCP) and Time to First Byte (TTFB)?
Question 5
Can multiple independent <Suspense> boundaries be used within a single page?

Next Lesson

Server Components vs Client Components ("use client" boundary)

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext