Loading and Streaming
A Trailhead trail page loads its details in 100 milliseconds but its weather forecast takes three seconds. Without help, the hiker clicks a trail and stares at the old page for three seconds, wondering if the click worked. The fix is to show something at once, and send each part of the page the moment it is ready.
The rule
Show a fallback at once; stream each part the moment it is ready.
loading.tsx gives a route segment an instant loading screen:
// app/trails/[slug]/loading.tsx
export default function Loading() {
return <div className="skeleton">Loading trail…</div>;
}Next.js wraps the segment's page in a React <Suspense> boundary with this as the fallback. On navigation, the layouts above stay visible and usable, the skeleton appears straight away, and the real page replaces it when it is ready.
<Suspense> does the same for any part of a page. Wrap the slow component, and the rest does not wait for it:
// app/trails/[slug]/page.tsx
import { Suspense } from "react";
export default async function TrailPage({ params }) {
const { slug } = await params;
const trail = await getTrail(slug); // fast
return (
<article>
<h1>{trail.name}</h1>
<p>{trail.distanceKm} km</p>
<Suspense fallback={<p>Checking the weather…</p>}>
<Forecast lat={trail.lat} lon={trail.lon} /> {/* slow, async */}
</Suspense>
</article>
);
}This works through streaming. The server does not wait to build the whole page. It sends the HTML in chunks over one response: first the layout, the trail details and the fallback; later, when Forecast finishes, its HTML plus a tiny script that swaps it into place. The browser shows each chunk as it arrives.
Each <Suspense> boundary is an independent unit: two slow components in two boundaries stream in whichever order they finish.
The shortcut
Draw a box around each slow thing. Anything that waits on a slow source goes in its own <Suspense> box with a fallback shaped like the real content. loading.tsx is simply the box around the whole page.
0 ms: the click
The layout stays;
loading.tsxshows the skeleton instantly.
The trap is one giant boundary. If everything sits inside a single <Suspense>, everything waits for the slowest part, and you are back to a long blank wait.
Drills
Answer fast — trust the rule.
What does loading.tsx do for its route segment?
While a trail page is loading, what happens to the layouts above it?
What is streaming, in this context?
Two slow widgets share one <Suspense> boundary. When do they appear?
Remember
- Show a fallback at once; stream each part the moment it is ready.
- Shortcut: draw a
<Suspense>box around each slow thing;loading.tsxis the box around the page. - Trap: one giant boundary makes everything wait for the slowest part.
