loading.tsx lets you show an instant loading state for a route while its data-fetching Server Components are still resolving, without writing any manual loading state logic. This lesson explains how it works under the hood.
loading.tsx Is a Suspense Boundary
When you add a loading.tsx file next to a page.tsx, Next.js automatically wraps that page in a React <Suspense> boundary, using your loading.tsx component as the fallback. As soon as the user navigates to the route, Next.js shows the loading UI instantly, then swaps in the real page content once its data has finished loading on the server.
This means users get instant feedback on navigation — no blank screen while await fetch(...) calls resolve inside a Server Component — without you writing a single isLoading state variable.
Visiting /dashboard shows "Loading dashboard..." immediately, then swaps to the real content once getStats() resolves.
loading.tsx File Convention
app/
dashboard/
loading.tsx // fallback UI for this segment
page.tsx // the actual, potentially slow, page
loading.tsx must default-export a component with no required props.
It automatically applies to the page.tsx in the same folder and to any nested routes beneath it.
It has no effect if the page has no async data fetching that would actually suspend.
You can nest multiple loading.tsx files at different levels for more granular loading states.
Loading UI Cheat Sheet
How loading.tsx behaves across the route tree.
Scenario
Behavior
loading.tsx in a route folder
Shown instantly on navigation to that route
No loading.tsx present
Browser waits with no visual feedback until content is ready
Nested loading.tsx files
Each segment can show its own, more specific loading state
Underlying mechanism
Automatic React <Suspense> boundary
Manual Suspense for Individual Components
loading.tsx covers an entire route segment, but you can also wrap individual slow components in your own <Suspense> boundary for more granular streaming — showing the rest of the page immediately while just one slow section loads in.
This pattern, called streaming, is covered in more depth in its own lesson later in this course.
Why This Improves Perceived Performance
Without loading.tsx, a slow Server Component leaves the browser showing the previous page (or a blank tab) until the entire new page's data resolves. loading.tsx gives immediate visual feedback the instant navigation starts, which measurably improves how fast an app feels even when the actual data fetch takes the same amount of time.
Common Mistakes
Expecting loading.tsx to show if the page has no async data fetching to actually suspend on.
Building a custom skeleton loader with useState/useEffect when loading.tsx already solves the problem declaratively.
Forgetting loading.tsx also applies to all nested routes beneath its folder, not just the immediate page.
Making the loading UI itself slow or heavy, defeating the purpose of instant feedback.
Key Takeaways
loading.tsx automatically wraps a route's page in a React <Suspense> boundary.
It shows instantly on navigation and is replaced once the page's data finishes loading.
It applies to the page in the same folder and to all nested routes beneath it.
You can also add manual <Suspense> boundaries around individual slow components for finer control.
Loading UI improves perceived performance even when actual load time is unchanged.
Pro Tip
Keep loading.tsx visually simple and fast to render — a lightweight skeleton or spinner — since it needs to appear instantly; save your more detailed, styled loading states for components wrapped in their own manual <Suspense> boundaries where you have finer control over timing.
You now understand loading states. Next, learn how error.tsx and not-found.tsx handle error and 404 scenarios gracefully.