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.tsxexport 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.
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> );}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
It also covers the initial server render — it's an automatic Suspense boundary, not just a client-side spinner.
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.