DEV Community

Cover image for Data Fetching Strategies in Next.js - SSR, SSG, ISR, and RSC

Data Fetching Strategies in Next.js - SSR, SSG, ISR, and RSC

“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

  1. Why data fetching strategy matters
  2. Quick comparison table
  3. Server-Side Rendering (SSR)
  4. Static Site Generation (SSG)
    • 4b Incremental Static Regeneration (ISR)
  5. React Server Components (RSC)
  6. App Router vs Pages Router
  7. Caching in App Router
  8. Real-world app architecture
  9. Common mistakes
  10. Stats
  11. Interesting Facts
  12. FAQs
  13. Summary
  14. 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 }
 }
}
Enter fullscreen mode Exit fullscreen mode

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 }
 }
}
Enter fullscreen mode Exit fullscreen mode

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
 }
}
Enter fullscreen mode Exit fullscreen mode

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
 }
}
Enter fullscreen mode Exit fullscreen mode

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 })
}
Enter fullscreen mode Exit fullscreen mode

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>
 )
}
Enter fullscreen mode Exit fullscreen mode

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

Interesting Facts

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)