loading.js in Next.js is a special file that gives a route segment an instant loading state. Next.js wraps the segment's page in a Suspense boundary using this component as the fallback, so the fallback appears immediately while the page content streams in.
Where the file goes
Placement is what activates this convention: the file only covers the segment it sits in. Place loading.js next to the page it belongs to, so for a dashboard route that means app/dashboard/loading.tsx alongside app/dashboard/page.tsx.
// app/dashboard/loading.tsx
export default function Loading() {
return <p aria-live="polite">Loading dashboard</p>;
}When a user navigates to the dashboard, this fallback renders first, then the page swaps in once its data is ready.
What loading.js wraps
loading.js wraps the page, not-found, and any nested layout in its segment. It does not wrap the segment's own layout, template, or error file.
| File | Wrapped by loading.js |
|---|---|
| page.js | Yes |
| not-found.js | Yes |
| nested layout.js | Yes |
| layout.js | No |
| error.js | No |
A slow layout still blocks the fallback unless its data fetch is moved into the page or wrapped in its own Suspense boundary. Because loading.js wraps the page and nested layouts, one fallback covers everything inside the segment below the current layout.
Building a skeleton fallback
A good fallback mirrors the shape of the real content, so the swap feels smooth. For a list, render a few gray bars; for a profile, render the avatar slot and name line. Keep it light, because this component is what every navigation shows while the real page loads.
The fallback is a Server Component by default. Add the use client directive only when the loading UI needs interactivity, which most skeletons do not. A static skeleton also avoids layout shift, because the space is reserved before the real content arrives.
The layout caveat
If the layout reads runtime data such as cookies, headers, or an uncached fetch, loading.js cannot show a fallback for it. What happens next depends on the caching model.
Without Cache Components, navigation simply blocks until the layout finishes rendering, which is the most common reason a loading state appears to do nothing. With Cache Components enabled in Next.js 16, the uncached access must be wrapped in its own Suspense boundary, and Next.js raises a build-time error until it is.
Either way the fix is the same: move the personalization into the page, or wrap it in a Suspense boundary inside the layout, so the shell can render instantly.
Instant loading states on navigation
On navigation, the fallback is prefetched, so it appears immediately unless the prefetch has not finished yet. Navigation stays interruptible, meaning the user can move to another route before this one loads, and shared layouts remain interactive while the new segment renders. For the mechanism behind this, see streaming in Next.js, and for finer control see Suspense boundaries.
Rune AI
Key Insights
- loading.js shows fallback UI while a segment streams in.
- It wraps the page, not-found, and nested layouts in Suspense.
- It does not wrap the layout, template, or error file.
- The fallback is prefetched, so navigation stays instant.
- Slow layout data must be moved into the page or wrapped in Suspense.
Frequently Asked Questions
Does loading.js wrap the layout too?
Can loading.js be a Client Component?
Why is my fallback not showing?
Conclusion
loading.js gives a route segment an instant fallback by wrapping its page in a Suspense boundary. It does not cover the segment's own layout, so slow layout work must be moved or wrapped separately.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.