The Ultimate Guide to Rendering in Next.js: SSR, SSG, ISR, CSR, PPR & Cache Explained

Search for a command to run...

No comments yet. Be the first to comment.
Meta Description: Learn how to convert your Next.js website into an Android app using Capacitor on Windows. Step-by-step guide with Android Studio setup, APK generation, and deployment. If you've alre

This is Part 2 of my Next.js Caching series. In Part 1, we covered Browser Cache, CDN, Router Cache, Full Route Cache, Data Cache, unstable_cache, and use cache. Previously... We learned that a requ

When someone opens your website, does Next.js immediately query your database? Not always. A request may pass through multiple cache layers before your database is even touched. The more requests serv

While building My Project, one of the biggest challenges wasn't building the UI—it was deciding how to cache data correctly. I wanted my application to: ⚡ Feel instant while navigating 🔍 Remain SEO

Akash Blog
19 posts
If you've been building with React or Next.js, you've probably heard terms like:
SSR
SSG
ISR
CSR
PPR
React Server Components
unstable_cache
At first, they all sound like different ways of saying:
"Render a webpage."
But they actually solve very different problems.
After building several production Next.js applications, I realized that choosing the wrong rendering strategy can make your application slower, more expensive, or harder to maintain.
This guide explains each rendering method from a practical perspective, when to use it, and how they all fit together.
Before diving into rendering strategies, it's important to understand the difference.
React is only a UI library.
By itself, React renders everything in the browser.
Browser
↓
Downloads JavaScript
↓
Runs React
↓
Page Appears
This is called Client-Side Rendering (CSR).
Next.js extends React by allowing pages to render:
On the server
During build time
Incrementally
Partially
Or entirely on the client
That's why Next.js offers multiple rendering strategies.
User
↓
HTML Shell
↓
Download JS
↓
Fetch API
↓
Render UI
Everything happens in the browser.
Example:
'use client'
const { data } = useSWR('/api/posts')
Great interactivity
Perfect for dashboards
Minimal server work
Slower first load
Poor SEO
Users wait for JavaScript
Admin panels
Internal dashboards
Authenticated apps
Highly interactive pages
Instead of sending an empty page...
Next.js renders everything on the server for every request.
User
↓
Server
↓
Database
↓
HTML
↓
Browser
Example:
export default async function Page() {
const posts = await getPosts()
return <Posts posts={posts} />
}
Every refresh executes the server code again.
Fresh data
Excellent SEO
Faster first paint
Higher server cost
Slower response if database is slow
News
Search results
User profiles
Personalized pages
Instead of rendering when users visit...
Pages are generated during build time.
Build
↓
Generate HTML
↓
Deploy
↓
Serve Static File
No server code runs when users visit.
Example:
npm run build
creates
about.html
pricing.html
contact.html
Extremely fast
Zero database queries
Cheap hosting
Content becomes outdated
Requires rebuilding
Landing pages
Documentation
Blogs
Marketing sites
ISR combines SSG with automatic regeneration.
User
↓
Cached Page
↓
TTL Expires
↓
Background Regeneration
Example:
export const revalidate = 60
Meaning:
Generate once
↓
Cache 60 seconds
↓
Regenerate automatically
Users always receive a cached page while regeneration happens in the background.
Almost static performance
Fresh content
Lower server costs
Ecommerce
Product pages
Restaurant menus
CMS websites
One of the newest rendering strategies in Next.js.
Instead of choosing between SSR and SSG...
You can mix both.
Static Header
↓
Static Hero
↓
Static Footer
↓
Dynamic Products
↓
Dynamic Notifications
Static parts are served immediately.
Dynamic sections stream in later.
Faster loading
Better Core Web Vitals
Smaller TTFB
Great UX
Large pages with only a few dynamic sections.
Server Components aren't a rendering strategy.
They're a React feature.
They:
Run only on the server
Never ship JavaScript
Can access databases directly
Example:
export default async function Products() {
const products = await db.product.findMany()
return <ProductList products={products} />
}
No API route needed.
This is probably the most misunderstood feature.
It does not render pages.
Instead...
It caches expensive server functions.
Without cache:
Request
↓
Database
↓
Response
↓
Database Again
↓
Response
With cache:
Request
↓
Cache
↓
Response
Example:
const getRestaurants = unstable_cache(
async () => prisma.restaurant.findMany(),
['restaurants'],
{
tags: ['restaurants']
}
)
Now the database isn't queried every request.
Instead, Next.js serves cached results.
Instead of waiting for time...
You can invalidate cache immediately.
revalidateTag('restaurants')
Perfect after:
Creating a restaurant
Updating a menu
Deleting content
React
│
Client Rendering
│
Next.js
│
┌─────────────────────────────────┐
│ CSR │ SSR │ SSG │ ISR │ PPR │
└─────────────────────────────────┘
│
React Server Components
│
unstable_cache
│
Database / APIs
| Framework | CSR | SSR | SSG | ISR | PPR |
|---|---|---|---|---|---|
| React | ✅ | ❌ | ❌ | ❌ | ❌ |
| Next.js | ✅ | ✅ | ✅ | ✅ | ✅ |
| Remix | ✅ | ✅ | Limited | ❌ | ❌ |
| Astro | Partial | ✅ | ✅ | Partial | ❌ |
| Nuxt | ✅ | ✅ | ✅ | Partial | ❌ |
| SvelteKit | ✅ | ✅ | ✅ | Partial | ❌ |
| Scenario | Recommended |
|---|---|
| Admin Dashboard | CSR |
| Marketing Website | SSG |
| Blog | ISR |
| News Website | SSR |
| Ecommerce | ISR |
| User Profile | SSR |
| Documentation | SSG |
| Restaurant Menu | ISR |
| SaaS Dashboard | CSR |
| Hybrid Homepage | PPR |
❌ Using SSR for everything
❌ Using CSR for SEO pages
❌ Rebuilding for every CMS update
❌ Forgetting cache invalidation
❌ Calling the database repeatedly instead of caching
One thing that confused me when learning Next.js was SWR.
At first, I thought it was another rendering strategy like SSR or ISR.
It isn't.
SWR is a client-side data fetching library created by Vercel.
Think of it as a smart cache for API requests inside the browser.
Example:
'use client'
import useSWR from 'swr'
const fetcher = (url: string) => fetch(url).then(res => res.json())
export default function Users() {
const { data, error, isLoading } = useSWR('/api/users', fetcher)
if (isLoading) return <>Loading...</>
return <div>{data.name}</div>
}
Instead of manually doing:
useEffect(() => {
fetch(...)
}, [])
SWR automatically handles:
✅ Client-side caching
✅ Request deduplication
✅ Background revalidation
✅ Automatic refetch on window focus
✅ Retry on network failure
✅ Optimistic UI updates
This is how I remember it:
| Feature | unstable_cache |
SWR |
|---|---|---|
| Runs on | Server | Browser |
| Purpose | Cache expensive database/API functions | Cache API requests on the client |
| Used for | Prisma queries, external APIs, expensive computations | Dashboards, user profile, live UI |
| Invalidated by | revalidateTag() / revalidatePath() |
mutate() |
| Part of rendering? | ❌ No | ❌ No |
Whenever I forget where each fits, I remember it like this:
Database
│
▼
unstable_cache
(Server Cache)
│
▼
SSR / ISR / SSG / PPR
(Render HTML)
│
▼
Browser
│
▼
SWR
(Client Cache)
│
▼
User Interface
SSR → Render fresh HTML on every request.
SSG → Render once during build.
ISR → Static pages that automatically regenerate.
CSR → Render everything in the browser.
PPR → Mix static and dynamic rendering.
React Server Components → Server-only React components.
unstable_cache → Cache expensive server functions.
SWR → Cache and revalidate API requests in the browser.
There isn't a "best" rendering strategy.
Each solves a different problem.
A modern Next.js application often combines several of them:
SSG for static pages
ISR for content updates
SSR for personalized experiences
CSR for interactive dashboards
PPR for hybrid performance
React Server Components for efficient server logic
unstable_cache to reduce database load
Understanding when to use each is what separates a working application from a fast, scalable one.
Happy building! 🚀
Next.js Rendering Docs: https://nextjs.org/docs/app/building-your-application/rendering
React Server Components: https://react.dev/reference/rsc/server-components
Next.js Caching Guide: https://nextjs.org/docs/app/guides/caching
unstable_cache API: https://nextjs.org/docs/app/api-reference/functions/unstable\_cache