Next.js Rendering Strategies: SSR, SSG, and ISR
In Next.js architecture discussions, engineers are frequently asked:
Explain the differences between Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR). When would you use each?
To answer this, you need to understand when page rendering occurs, where cache structures sit, and how pages are revalidated.
1. Defining the Rendering Strategies
In the App Router, Next.js refers to these behaviors as Static Rendering vs. Dynamic Rendering, controlled by your use of data-fetching strategies, route configurations, and cache settings.
A. Static Site Generation (SSG)
- Concept: The page is rendered at build time (when you run
next build). The compiled HTML, JS, and CSS are written to disk and can be distributed to a CDN edge immediately. - Data Fetching: All database queries or API requests are performed during compile time.
- Best Use: Marketing pages, blog posts, documentation, and landers where the content does not change frequently.
B. Server-Side Rendering (SSR) / Dynamic Rendering
- Concept: The page is rendered on-demand for each request. When a user visits the URL, the server executes data-fetching operations, renders the HTML, and responds to the browser.
- Data Fetching: Next.js automatically switches to Dynamic Rendering if it detects dynamic functions (like reading cookies or header values) or if a data fetch requests
cache: 'no-store'. - Best Use: Real-time user dashboards, search result pages, shopping carts, or pages containing personalized user info.
C. Incremental Static Regeneration (ISR)
- Concept: Allows you to create or update static pages after you've built your site, without rebuilding the entire project. It serves static pages from a cache but regenerates them in the background after a specified duration.
- Data Fetching: Controlled using the
next: { revalidate: number }option on a fetch call, or by declaring a route segment configurationexport const revalidate = 60. - Best Use: Large catalog websites, e-commerce listings, or news blogs where data changes occasionally but doesn't require instantaneous updates.
2. Comparison Summary
| Strategy | When is Page Rendered? | Cached at Edge (CDN)? | Request Latency |
|---|---|---|---|
| SSG | At Build Time | Yes, permanent | Extremely Low |
| SSR | At Request Time | No | Medium |
| ISR | Build time + Background Revalidation | Yes, temporary | Low |
3. Implementation Patterns (App Router)
SSG (Default behavior)
// app/blog/[slug]/page.tsx
// Next.js automatically compiles this statically
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({ slug: post.id }));
}
export default async function Page({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return <article>{post.title}</article>;
}SSR (Dynamic Rendering)
// app/dashboard/page.tsx
export default async function Dashboard() {
// force-dynamic or fetch with no-store forces SSR
const res = await fetch("https://api.example.com/stats", {
cache: "no-store",
});
const data = await res.json();
return <div>Stats: {data.value}</div>;
}ISR (Incremental Regeneration)
// app/products/page.tsx
export const revalidate = 3600; // revalidate every hour
export default async function Products() {
const res = await fetch("https://api.example.com/products");
const products = await res.json();
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}Key Takeaways
- Static Rendering: By default, Next.js statically renders pages (SSG) to maximize performance.
- Incremental Static Regeneration: Use ISR for content that is dynamic but doesn't change on every request to reduce load on database backends.
- Server-Side Rendering: Use SSR only when page content is highly personalized or changes frequently.