Loading and Streaming in Next.js
The Restaurant Analogy 🍽️
Imagine you walk into a busy restaurant. You’re hungry! What happens next?
Old way (no loading UI): You stand there staring at nothing. No menu. No waiter. No clue if anyone even knows you exist. Awkward!
New way (with Loading UI): A friendly waiter immediately says “Welcome! Here’s some water while I get your menu.” You feel cared for. You know food is coming.
That’s exactly what Loading UI does in Next.js! It tells your users: “Hey, we see you! Good stuff is on the way.”
What is Loading UI?
When your app needs to fetch data from a server, it takes time. Without Loading UI, users see… nothing. A blank screen. They might think the app is broken!
Loading UI shows something friendly while waiting. A spinner. A skeleton. A fun animation. Anything that says “please wait.”
Why Does This Matter?
User clicks button
↓
App fetches data (takes 2 seconds)
↓
❌ Without Loading UI: Blank screen (user panics)
✅ With Loading UI: "Loading..." message (user relaxes)
Simple truth: Happy users wait patiently when they know something is happening.
The loading.js File
Here’s something magical. Next.js has a special file called loading.js. Just create it, and boom — automatic loading states!
How It Works
Put a file named loading.js (or loading.tsx) in any folder inside your app directory. Next.js will automatically show it while that page loads.
app/
├── dashboard/
│ ├── page.js ← Your actual page
│ └── loading.js ← Shows while page loads
A Simple Example
loading.js:
export default function Loading() {
return (
<div className="spinner">
Loading your dashboard...
</div>
);
}
That’s it! No extra code. No configuration. Next.js handles everything.
The Magic Behind It
graph TD A[User visits /dashboard] --> B[Next.js checks folder] B --> C{loading.js exists?} C -->|Yes| D[Show loading.js content] C -->|No| E[Show blank until ready] D --> F[Page data fetches] F --> G[Replace with page.js content]
Key insight: The loading file wraps your page automatically. Users see the loading state first, then the real content smoothly replaces it.
Streaming SSR: The Pizza Delivery Story
Let’s talk about Streaming SSR (Server-Side Rendering).
The Old Pizza Problem
Imagine ordering 5 pizzas for a party:
Old way: The delivery person waits until ALL 5 pizzas are ready. Then brings them together. Your guests are starving!
Streaming way: Each pizza comes as soon as it’s ready. First pizza arrives in 5 minutes. Guests start eating immediately!
How Streaming Works
With traditional SSR, the server builds the ENTIRE page before sending anything. Slow parts block fast parts.
With Streaming SSR, the server sends parts of the page as they become ready. Fast parts show up immediately!
graph TD A[Browser requests page] --> B[Server starts building] B --> C[Header ready - SEND IT] C --> D[Sidebar ready - SEND IT] D --> E[Main content ready - SEND IT] E --> F[Comments ready - SEND IT]
Real Example
Your page has:
- A header (fast: 50ms)
- User profile (medium: 500ms)
- Comments from database (slow: 2 seconds)
Without streaming: User waits 2+ seconds for anything.
With streaming:
- Header appears at 50ms
- Profile appears at 500ms
- Comments appear at 2 seconds
Same total time, but users see progress!
Code Example
// app/page.js
import { Suspense } from 'react';
import Comments from './Comments';
export default function Page() {
return (
<main>
<h1>My Blog Post</h1>
<p>This appears instantly!</p>
<Suspense fallback={<p>Loading comments...</p>}>
<Comments />
</Suspense>
</main>
);
}
The <Suspense> wrapper tells Next.js: “Stream this part separately. Show the fallback while waiting.”
Progressive Rendering: Building a House
Think of Progressive Rendering like building a house.
You Don’t Wait for the Whole House
When builders construct a house, do they hide it behind a curtain until it’s 100% complete? No! You see:
- First, the foundation
- Then the walls go up
- Then the roof
- Then windows and doors
- Finally, the paint and finishing
At each stage, you can see progress. You feel confident it’s coming together.
Progressive Rendering in Next.js
Your web page works the same way. Different parts load at different speeds:
| Part | Speed | When Users See It |
|---|---|---|
| Shell/Layout | Instant | Immediately |
| Static text | Very fast | Almost instantly |
| Images | Medium | As they download |
| Database data | Slower | When fetched |
| External API | Slowest | When response arrives |
The Key Ingredients
Progressive rendering uses:
loading.js— Shows while whole routes load<Suspense>— Wraps slow components- Streaming — Sends HTML in chunks
- React Server Components — Run on server, stream to browser
Complete Example
// app/dashboard/page.js
import { Suspense } from 'react';
import Stats from './Stats';
import RecentOrders from './RecentOrders';
import Analytics from './Analytics';
export default function Dashboard() {
return (
<div>
{/* This shows immediately */}
<h1>Dashboard</h1>
{/* Stats load quickly */}
<Suspense fallback={<StatsSkeleton />}>
<Stats />
</Suspense>
{/* Orders take a moment */}
<Suspense fallback={<OrdersSkeleton />}>
<RecentOrders />
</Suspense>
{/* Analytics are slow */}
<Suspense fallback={<AnalyticsSkeleton />}>
<Analytics />
</Suspense>
</div>
);
}
What users experience:
- See “Dashboard” title instantly
- Stats skeleton appears, then real stats
- Orders skeleton appears, then real orders
- Analytics skeleton appears, then real data
Everything feels fast because something is always happening!
Skeleton Loaders: The Polished Touch
Instead of a boring “Loading…” text, use skeleton loaders. These are gray shapes that match your final content layout.
Why Skeletons Are Better
❌ "Loading..."
→ User has no idea what's coming
✅ [████████████] (skeleton card shape)
→ User sees a card is coming!
Skeletons reduce perceived wait time. The brain sees familiar shapes and thinks “almost ready!”
Simple Skeleton CSS
.skeleton {
background: linear-gradient(
90deg,
#e0e0e0 25%,
#f0f0f0 50%,
#e0e0e0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
Putting It All Together
Here’s the complete picture:
graph TD A[User visits page] --> B[loading.js shows instantly] B --> C[Server starts streaming HTML] C --> D[Fast parts appear first] D --> E[Suspense boundaries hold slow parts] E --> F[Each part streams when ready] F --> G[Full page complete]
The Recipe for Fast Apps
- Add
loading.jsto your route folders - Wrap slow components in
<Suspense> - Use skeleton loaders as fallbacks
- Let Next.js stream everything automatically
Quick Reference
| Feature | What It Does | How to Use |
|---|---|---|
loading.js |
Auto loading for routes | Create file in route folder |
<Suspense> |
Wrap individual components | Import from React |
| Streaming | Send HTML in chunks | Automatic with above! |
| Skeletons | Pretty loading shapes | CSS + fallback prop |
Remember This!
Think of your web app like that restaurant:
- loading.js = The waiter who greets you immediately
- Streaming = Appetizers arriving before the main course
- Progressive Rendering = Each dish coming when it’s ready
- Skeletons = The menu showing you what’s coming
Your users should never stare at a blank screen wondering if something broke.
Show them progress. Keep them engaged. Make waiting feel short.
That’s the power of Loading and Streaming in Next.js! 🚀