LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1814 min read

Loading UI & Streaming

Give every route an automatic loading state with loading.tsx, built on React Suspense and streaming HTML.

The Problem: Slow Data

When a Server Component awaits a slow API call, the naive approach blocks the entire page from rendering until that data arrives — the visitor sees a blank screen the whole time. Next.js solves this with built-in streaming.

loading.tsx

Adding a loading.tsx file next to a page.tsx gives that route segment an instant loading UI, shown immediately while the page's data is still being fetched on the server.

app/dashboard/
├── page.tsx → slow, fetches data from the server
└── loading.tsx → shown instantly while page.tsx is loading
// app/dashboard/loading.tsx
export default function Loading() {
return <p>Loading dashboard…</p>;
}

How It Works: Suspense & Streaming

Behind the scenes, Next.js automatically wraps the page in a React <Suspense> boundary using loading.tsx as its fallback. The server streams the loading UI to the browser instantly, then streams in the real content as soon as it's ready — without waiting for the whole page.

Request arrives
↓
Server sends loading.tsx immediately
↓
Server keeps fetching page data
↓
Server streams in the real page content
↓
Browser swaps loading UI for final content

Granular Loading with <Suspense>

loading.tsx covers a whole route. For finer control — like showing the rest of a page immediately while only one slow widget shows a spinner — wrap that specific component in your own <Suspense> boundary.

import { Suspense } from 'react';
export default function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<p>Loading stats…</p>}>
<SlowStatsWidget />
</Suspense>
</div>
);
}
Result

The heading renders immediately; only the widget waits behind its own fallback — this is the same streaming mechanism as loading.tsx, applied to a smaller piece of the page.

Common Beginner Mistakes

Expecting loading.tsx to cover client-side navigation clicks only

It also covers the initial server render — it's an automatic Suspense boundary, not just a client-side spinner.

Adding loading.tsx to every folder "just in case"

Only add it where a route's data fetch is genuinely slow enough to need it — unnecessary boundaries add visual flicker for fast routes.

FAQs

Yes — streaming is a server/HTML-level feature, so the loading state and streamed content both work even before any client JavaScript runs.

Yes — loading.tsx is just a regular component, so you can use CSS animations or a skeleton UI inside it like any other component.

Summary

loading.tsx and <Suspense> let Next.js show something useful immediately, then stream in real content as it becomes ready. Next, you'll learn the equivalent pattern for handling errors.

Next Lesson →

Error Handling