Next.js Loading UI: Instant Shells, Streamed Content
Next.js's `loading.js` shows an instant UI shell while streaming in server-rendered content. Use it for data-heavy pages to improve perceived performance. The footgun: a loading UI only wraps its own route segment and children, not parent layouts.
WHY IT EXISTS Traditional server-rendering can be all-or-nothing. If one data fetch is slow, the entire page waits, leaving the user with a blank screen. This creates poor perceived performance, especially on slower connections or with complex data dependencies.
THE MENTAL MODEL Think of a loading.js file as an automatic placeholder for a specific part of your page. When you navigate to a route, Next.js immediately sends the static parts of the page (the layout) and your loading UI. While the user sees this shell, Next.js fetches data on the server and streams the finished content to the browser to swap in. It's a placeholder that gets replaced by the real thing.
HOW IT WORKS By creating a file named loading.js (or .tsx) inside a folder in your app directory, you define a loading UI for that route segment. Next.js automatically wraps the segment's page.js and its children in a React Suspense boundary, using your loading.js component as the fallback. This allows the server to render and stream content incrementally.
WHEN TO USE IT Use loading.js in any route segment that performs data fetching or has a non-trivial rendering time. It's ideal for dashboards, user profiles, or product pages where you can show a meaningful skeleton or spinner while waiting for dynamic data. This dramatically improves the user's perception of speed.
WHEN NOT TO USE IT Don't use it if the page segment is purely static, as there's nothing to wait for. Also, be mindful of creating a "waterfall" of spinners. If every nested component has its own loading state, the UI can feel jittery and disjointed. It's often better to have one well-placed loading UI for a larger section.
ONE CANONICAL EXAMPLE A user profile page at app/users/[id]/page.js fetches user data. You create app/users/[id]/loading.js with a skeleton component that mimics the profile layout. When a user navigates to /users/123, they immediately see the main site layout and the profile skeleton. In the background, Next.js fetches the data, renders the full profile page on the server, and streams it down to replace the skeleton.
Read the original → nextjs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.