“Performance is not a feature - it’s the foundation. Next.js gives you the tools to build it right.”
Key Takeaways
- Next.js provides multiple data fetching strategies depending on performance and freshness needs.
- SSR fetches data on every request and is best for dynamic content.
- SSG generates pages at build time, making it extremely fast.
- ISR updates static pages after deployment without full rebuilds.
- RSC (React Server Components) is the modern default in App Router.
- Caching in Next.js is controlled using fetch options like cache and revalidate.
- Real-world apps use a combination of SSR, SSG, ISR, and RSC - not just one.
Index
- Why data fetching strategy matters
- Quick comparison table
- Server-Side Rendering (SSR)
- Static Site Generation (SSG)
- 4b Incremental Static Regeneration (ISR)
- React Server Components (RSC)
- App Router vs Pages Router
- Caching in App Router
- Real-world app architecture
- Common mistakes
- Stats
- Interesting Facts
- FAQs
- Summary
- Conclusion
Introduction
Why does data fetching strategy actually matter?
In a classic React app, data fetching is simple: useEffect fires after the component mounts, you hit an API, and update state.
Easy to reason about - but there’s a problem:
The user sees a blank or loading screen until JavaScript executes and the fetch completes.
For small apps, this is fine.
At scale, it becomes a serious UX and SEO issue.
How Next.js Solves This
“Modern web development is not about fetching data - it’s about fetching it intelligently.”
Next.js lets you decide:
Where and when data should be fetched
Each strategy is a tradeoff between:
- Freshness
- Performance
- Server cost
- Complexity
Mental Model
Think of it as a spectrum:
- Fully Dynamic → SSR
- Fully Static → SSG
- In Between → ISR + RSC
Quick Reference - All Strategies at a Glance
Important Note
RSC is not a replacement for SSR, SSG, or ISR.
It’s a new rendering model that can behave like any of them.
Strategy 01
Server-Side Rendering (SSR)
When a request comes in:
Next.js fetches data on the server before sending HTML
Pages Router Example
export async function getServerSideProps(context) {
const { req } = context
oop-
const session = await getSession(req)
if (!session) {
return {
redirect: {
destination: '/login',
permanent: false
}
}
}
const res = await fetch(`https://api.example.com/users/${session.userId}`)
const user = await res.json()
return {
props: { user }
}
}
Key Behavior
- Runs on every request
- Full HTML is returned
- No loading state on client
When to Use SSR
- User-specific content
- Authentication logic
- Real-time data
- Accessing cookies/headers
When NOT to Use SSR
- Same data for all users
- Rarely changing content
- Performance-sensitive pages
Important
SSR adds latency - your API speed = your page speed.
Strategy 02
Static Site Generation (SSG)
SSG generates pages at build time and serves static HTML.
Example
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts')
const data = await res.json()
return {
props: { data }
}
}
Dynamic Routes Example
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
return {
paths: posts.map(post => ({
params: { slug: post.slug }
})),
fallback: false
}
}
When to Use SSG
- Blogs
- Docs
- Landing pages
Tradeoff
- Very fast
- Not real-time
Strategy 03
Incremental Static Regeneration (ISR)
ISR = SSG + automatic updates
How It Works
- Serve static page
- After interval → regenerate in background
- Next request gets fresh page
Example
export async function getStaticProps() {
const res = await fetch('https://api.example.com/products')
const products = await res.json()
return {
props: { products },
revalidate: 60
}
}
Key Insight
Revalidation only happens when a request comes
No traffic = no update
On-Demand ISR (Better Approach)
export default async function handler(req, res) {
if (req.headers['x-webhook-secret'] !== process.env.WEBHOOK_SECRET) {
return res.status(401).json({ message: 'Unauthorized' })
}
const { slug } = req.body
await res.revalidate(`/products/${slug}`)
return res.json({ revalidated: true })
}
When to Use ISR
- Product pages
- News
- CMS-driven content
Strategy 04 (Modern Default)
React Server Components (RSC)
“RSC changes the game: less JavaScript, better performance, cleaner architecture.”
In App Router:
Components run on the server by default
Example
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
next: { revalidate: 60 }
})
return res.json()
}
export default async function Page() {
const products = await getProducts()
return (
<div>
{products.map(p => (
<p key={p.id}>{p.name}</p>
))}
</div>
)
}
Controlling Behavior
fetch(url, { cache: 'force-cache' }) // SSG
fetch(url, { cache: 'no-store' }) // SSR
fetch(url, { next: { revalidate: 60 } }) // ISR
Key Benefits
- No useEffect
- No client-side fetching
- Smaller JS bundle
Important Rule
Client components cannot import server components
Data flows server → client
Architecture
App Router vs Pages Router
Pages Router
- getServerSideProps / getStaticProps
- Page-level fetching
- Older system
App Router
- Async components
- Component-level fetching
- Server-first approach
- Supports streaming App Router is the future
Deep Dive
Caching in App Router
There are 4 cache layers:
Common Issue
“Why is my data not updating?”
Usually due to Router cache
Fix
router.refresh()
Revalidation Example
import { revalidateTag } from 'next/cache'
revalidateTag('products')
Production Patterns
Real-World Architecture
E-commerce
- Homepage → SSG
- Product Page → ISR
- Cart → SSR
- Layout → RSC
SaaS
- Landing → SSG
- Dashboard → SSR
- Docs → ISR
Real apps use combination of strategies
“The best data fetching strategy is not SSR or SSG - it’s choosing the right one at the right time.”
Anti-Patterns
Common Mistakes
1. Using SSR everywhere
Expensive + slow
Use ISR instead
2. Ignoring server/client boundary
Causes runtime errors
3. No error handling
Can crash entire page
4. Fetching in client unnecessarily
Adds JS + loading delay
5. Misunderstanding ISR timing
Low traffic = stale data
Stats
- According to Vercel, static generation can significantly improve performance by serving pre-rendered pages from a CDN, reducing server computation.Source: https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation
- Next.js has millions of weekly downloads and is one of the most widely used React frameworks.Source: https://www.npmjs.com/package/next
- Next.js is used by companies like Netflix, TikTok, and Hulu for high-performance applications.Source: https://nextjs.org/showcase
Interesting Facts
- Next.js was created and is maintained by Vercel.Source: https://nextjs.org
- Incremental Static Regeneration (ISR) was introduced in Next.js 9.5.Source: https://nextjs.org/blog/next-9-5
- React Server Components (RSC) became stable with the App Router in Next.js 13.Source: https://nextjs.org/blog/next-13
- Next.js enables full-stack development by combining frontend and backend capabilities in a single framework.Source: https://nextjs.org/docs
FAQ
1. Is SSR outdated?
No - it’s still essential for dynamic and user-specific data.
2. Is RSC replacing SSR/SSG?
No - it enhances them and gives more flexibility.
3. Can we mix all strategies?
Yes - and that’s the recommended approach.
4. Which is best for SEO?
SSG and SSR both are great for SEO.
5. Can ISR work with dynamic routes?
Yes
6. Where to store API keys?
Server-side only
7. App Router or Pages Router?
New projects → App Router
8. How to avoid waterfall fetches?
Use RSC
Summary
The Decision Tree
Ask:
Does data change per user?
- Yes → SSR / RSC (no-store) Does data rarely change?
- Yes → SSG Does it update periodically?
- Yes → ISR Using App Router?
- Use RSC + fetch control
Final Insight
- Use Server Components for data
- Use Client Components for interactivity
- Use ISR for scalability
Conclusion
Data fetching in Next.js is not about memorizing functions…
It’s about choosing the right strategy at the right time.
- Use SSR for dynamic data
- Use SSG for static content
- Use ISR for balance
- Use RSC for modern optimization
Once you understand this:
- Your apps become faster
- Your architecture becomes scalable
- Your performance improves significantly
About the Author:Vatsal is a web developer at AddWebSolution. Building web magic with Laravel, PHP, MySQL, Vue.js & more.


Top comments (0)