When you build a website with Next.js, every page has to decide how it gets its data. Should it be generated once and served as a static file? Rendered fresh on every request? Or something in between? These three choices—Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR)—form the backbone of your site's performance, scalability, and freshness.
The problem is that the terminology makes them sound more complicated than they are. SSG, SSR, ISR—they're just different ways of answering one simple question: When does the work of building the page happen?
Once you understand that question, the rest falls into place. I've spent years building with all three, and the decision almost always comes down to two factors: how often the content changes, and how much you care about every user seeing the absolute latest version.
Let me walk through each strategy, the trade-offs, and how to choose between them. If you already know the basics of ISR, feel free to skip ahead to the comparison. But if you want a plain-English explanation first, you're in the right place.
SSG: The Fastest, But Most Rigid
Static Site Generation is the simplest and fastest rendering strategy. At build time, Next.js fetches the data, renders the page to HTML, and saves the result as a static file. That file sits on a CDN, ready to be served instantly to any user who requests it.
// app/posts/[slug]/page.tsx — Static Site Generation
export async function generateStaticParams() {
const posts = await fetch("https://api.example.com/posts").then((r) =>
r.json(),
);
return posts.map((post) => ({ slug: post.slug }));
}
export default async function PostPage({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(
(r) => r.json(),
);
return <article>{post.content}</article>;
}
The benefits are obvious. Static files are the fastest thing you can serve. They're cached globally, they don't hit your server, and they can handle enormous traffic spikes without breaking a sweat.
The downside is freshness. That static file was built at deploy time. If you update a blog post, fix a typo, or change a price, the static page won't reflect it until the next full rebuild. For a site with thousands of pages, rebuilding every time a single character changes is slow, wasteful, and annoying.
SSG is perfect for content that rarely changes: marketing pages, documentation, privacy policies, portfolio pieces. Anything that can be safely generated once and left alone.
SSR: Always Fresh, But Always Working
Server-Side Rendering takes the opposite approach. Instead of building the page at deploy time, the server builds it on every request. Each time a user visits the page, the server fetches the data, renders the component, and sends back fresh HTML.
// app/dashboard/page.tsx — Server-Side Rendering
export default async function DashboardPage() {
const revenue = await fetch("https://api.example.com/revenue").then((r) =>
r.json(),
);
const users = await fetch("https://api.example.com/users").then((r) =>
r.json(),
);
return <Dashboard revenue={revenue} users={users} />;
}
SSR guarantees that the user always sees the latest data. There's no cache to worry about, no stale content. If the data changes, the page changes.
But that freshness comes at a cost. The server has to do work on every single request. It fetches data, runs JavaScript, renders HTML. That takes time—maybe 100ms, maybe 500ms. Under heavy load, the server can become a bottleneck. And because the HTML is generated per request, you can't easily cache it on a CDN. Every user gets a bespoke page, which is great for personalization but terrible for performance.
SSR is the right choice for pages that require real-time data or user-specific content: dashboards, account settings, shopping carts. Anything where showing stale data could be a problem.
ISR: The Best of Both Worlds
Incremental Static Regeneration is the hybrid. It starts like SSG—pages are generated statically at build time. But it adds a revalidation interval. When the cached page gets older than that interval, the next request triggers a background regeneration. The user still gets the old page instantly, but the server updates the cache for the next person.
// app/products/[id]/page.tsx — ISR
async function getProduct(id: string) {
const res = await fetch(`https://api.example.com/products/${id}`, {
next: { revalidate: 60 }, // Revalidate every 60 seconds
});
return res.json();
}
export default async function ProductPage({ params }) {
const product = await getProduct(params.id);
return <ProductDetails product={product} />;
}
That revalidate: 60 is the magic. It tells Next.js: "This page is good for one minute. After that, serve the stale version and update it in the background."
The result? You get the performance of static generation with the freshness of dynamic rendering. The page loads instantly from cache. The server only does work when the cache expires. And because the regeneration happens in the background, users never wait.
On-demand revalidation takes this further. Instead of a timer, you trigger regeneration manually—usually from a CMS webhook. When a content editor publishes a new post, the CMS pings your API route, and you call revalidatePath. The page updates immediately, no timer involved.
ISR is the go-to for content that changes occasionally but doesn't need per-request freshness: blog posts, product pages, documentation, news articles. It's the sweet spot for most content-driven websites.
If you want a deeper dive into ISR itself, check out our complete ISR guide or the beginner-friendly explanation.
Side-by-Side Comparison
| SSG | SSR | ISR | |
|---|---|---|---|
| When does rendering happen? | At build time | On every request | At build time, then in background when stale |
| Freshness | Stale until next rebuild | Always fresh | Slightly stale (depends on revalidate interval) |
| Performance | Fastest (static CDN) | Slowest (server work per request) | Fast (static CDN, background updates) |
| Server load | Very low | High | Moderate |
| Best for | Rarely-changing content | Real-time or personalized content | Frequently-changing but not real-time content |
| Examples | Marketing pages, docs | Dashboards, account settings | Blog posts, product pages |
How to Choose: A Simple Decision Tree
Ask yourself three questions:
Does the content need to be different for each user? If yes, use SSR. Static pages can't be personalized without client-side tricks, and ISR shares one cached version for everyone.
Does the content change more than once a minute? If yes, use SSR. Even with a short revalidation interval, ISR will serve slightly stale data. For real-time feeds, SSR (or client-side fetching) is safer.
Do you care more about performance or freshness? If performance is the priority and you can tolerate a few minutes of staleness, use ISR. If freshness is critical and performance is secondary, use SSR.
For anything that fits the "content changes occasionally but not constantly" pattern, ISR is usually the best answer. It gives you static-level performance with dynamic-level freshness.
If you're still on the fence, our ISR vs SSR comparison focuses specifically on that decision. And if you're trying to optimize page speed overall, our post on why modern websites feel slower explains how rendering strategy affects user experience.
A Real Story: Migrating from SSR to ISR and Cutting Costs 70%
I once worked on a marketing site for a SaaS company. It had hundreds of pages—product features, pricing, blog posts, case studies—and every single one used SSR. The team had chosen SSR because the content was updated frequently, and they thought they needed the freshness.
The problem was performance and cost. Every page request triggered a database query and a serverless function invocation. On a typical day, the site was burning through thousands of compute hours. During a marketing campaign traffic spike, the bill nearly tripled.
I recommended ISR for everything except the user dashboard. The product and blog pages were cached with a 5-minute revalidation interval. The pricing page got a 1-minute interval because prices changed occasionally but not in real time.
The result? Page load times dropped from 400ms to under 80ms. Server costs fell by 70%. Content editors still saw their updates go live within minutes. And users actually had a faster experience, not a slower one.
That migration taught me that most content doesn't need per-request rendering. ISR's "stale-while-revalidate" approach is a perfect fit for any content that changes on a human timescale (minutes, not milliseconds). The only true SSR pages left were the ones where personalization or real-time accuracy actually mattered.
Common Misconceptions to Avoid
Misconception 1: "ISR is just static with a timer." No, it's more than that. ISR includes on-demand revalidation, which makes it as fresh as you need it to be, without the waste of periodic rebuilding.
Misconception 2: "SSR is always slow." For pages with low traffic, SSR is perfectly fine. The server can handle the load. But at scale, SSR becomes expensive unless you add caching layers, which essentially turn it into ISR.
Misconception 3: "SSG is dead because ISR exists." SSG still has its place for truly static content that never changes. If a page's content is set in stone, there's no reason to pay for background regeneration—just generate it once and forget it.
Misconception 4: "ISR can handle personalized content." No. ISR serves the same cached page to everyone. If your page needs per-user data, use SSR or client-side fetching for the personalized parts.
Wrapping Up
SSG, SSR, and ISR aren't competing philosophies—they're tools for different jobs. SSG is for content that never changes. SSR is for content that must be fresh and personalized. ISR is for everything in between.
The great thing about Next.js is that you can mix all three on a per-page basis. Your marketing pages can be SSG, your blog can be ISR, and your dashboard can be SSR. You don't have to choose one strategy for the whole site.
If you're building a new project, start with ISR for content-driven pages, reserve SSR for personalized or real-time pages, and use SSG for truly static content. That combination will give you the best balance of performance, freshness, and maintainability.
And if you want to learn more about implementing ISR, our complete guide covers everything from time-based revalidation to on-demand tags and error handling.
Now go build something fast.
Need help choosing the right rendering strategy for your Next.js project? Red Surge Technology builds performant, maintainable web applications that balance speed and freshness. Get in touch to discuss your project.