
Learn the differences between SSR and SSG in Next.js, when to use each rendering method, and how to choose the right approach for your project.
Next.js is a powerful React framework that enables developers to build fast, SEO-friendly web applications. One of the key features that sets it apart is its flexible data fetching strategies — namely SSR (Server-Side Rendering) and SSG (Static Site Generation). In this post, we’ll break down what these terms mean, when to use each, and show practical examples using modern Next.js App Router patterns.
With SSR, the HTML for a page is generated on the server at every single request. This ensures that the data is always fresh and up to date.
In the modern Next.js App Router, every Server Component is dynamic by default if you use dynamic functions or data fetching without explicit caching. You can also explicitly force dynamic rendering:
// app/products/page.tsx
import React from 'react';
// Forces dynamic server-side rendering on every request
export const dynamic = 'force-dynamic';
async function getProducts() {
const res = await fetch('[https://api.example.com/products](https://api.example.com/products)', { cache: 'no-store' });
return res.json();
}
export default async function ProductsPage() {
const products = await getProducts();
return (
<div>
<h1>Live Product List (SSR)</h1>
<ul>
{products.map((p: any) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
</div>
);
}
With SSG, the HTML is generated once at build time. The cached result is then served instantly to every user request.
By default, standard fetch requests in Next.js are cached aggressively, which gives you SSG out of the box:
// app/blog/page.tsx
import React from 'react';
async function getPosts() {
// Cached by default (SSG)
const res = await fetch('[https://api.example.com/posts](https://api.example.com/posts)');
return res.json();
}
export default async function BlogPage() {
const posts = await getPosts();
return (
<div>
<h1>Static Blog Posts (SSG)</h1>
<ul>
{posts.map((post: any) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
Next.js also allows incremental static regeneration, where static pages can be updated in the background after deployment without rebuilding the entire site.
async function getPosts() {
const res = await fetch('[https://api.example.com/posts](https://api.example.com/posts)', {
next: { revalidate: 60 }, // Revalidate every 60 seconds
});
return res.json();
}
| Use Case | Recommended Strategy |
|---|---|
| Product pages with live inventory | SSR |
| Blog posts & documentation | SSG or ISR |
| User dashboards & profiles | SSR (Dynamic) |
| Marketing landing pages | SSG |
| Frequently updated news | ISR or SSR |
Choosing between SSR and SSG depends entirely on your data requirements. When in doubt, use SSG for static, content-driven pages and SSR when data needs to be fresh on every click. With modern Next.js, mixing both approaches inside the same application has never been easier.