Next.js has become the de‑facto standard for building modern React applications, and the two most important rendering modes – Incremental Static Regeneration (ISR) and Server‑Side Rendering (SSR) – often raise questions when choosing an architecture. In this article we will look at their internal mechanisms, measure real render time, estimate resource costs, and advise when to pick one solution over the other.
How Does Incremental Static Regeneration Work?
ISR combines the benefits of static generation (SSG) with the ability to refresh content after deployment. On the first request Next.js generates HTML and stores it in cache (Edge or CDN). Subsequent requests return the cached file, while in the background, if the revalidate period defined in getStaticProps has elapsed, a regeneration process is triggered.
export async function getStaticProps() {
const data = await fetchAPI();
return {
props: { data },
revalidate: 60 // refresh every 60 s
};
}
The mechanism relies on the unstable_revalidate function (since Next.js 13) or an internal Lambda/Edge queue. This means we don’t have to keep an entire server running – only a short function that generates a new version of the page.
Server‑Side Rendering – Classic with Modern Cache
SSR renders the page on every request, invoking getServerSideProps. The result is sent directly to the browser, and then React “hydrates” the interactive UI. In practice SSR requires a continuously running Node.js process, which leads to higher memory and CPU usage.
export async function getServerSideProps(context) {
const data = await fetchAPI(context.params.id);
return { props: { data } };
}
SSR performance can be improved by adding a cache layer (e.g., stale‑while‑revalidate on Vercel Edge) or memoising queries, but each request still needs to be processed by Node.
Comparison of ISR and SSR in Next.js – Render Times and Costs
- Cold start ISR: the first request after deployment generates HTML – cost similar to SSR but one‑time.
- Warm ISR: subsequent requests return a static file from CDN – latency 20‑40 ms with global distribution.
- SSR: every request runs the full Node cycle – typically 120‑250 ms depending on query complexity.
- Costs: ISR pays only for CDN storage and occasional Lambda invocations; SSR pays for continuously running instances (CPU, RAM) and data transfer.
In practice the differences become critical at high RPS (requests per second). At 10 000 RPS ISR can handle traffic with minimal cost, while SSR requires horizontal scaling, which raises the bill.
When to Use ISR and When Not To
- ISR: content that changes rarely (e.g., blog, product catalog), SEO‑important, but tolerant of
revalidatedelay. - SSR: data that needs immediate updates (e.g., cart, post‑login personalization), dynamic UI dependent on session.
If your application needs a mix – you can combine both approaches in one project, defining getStaticProps for public pages and getServerSideProps for protected sections.
Migration Pitfalls from SSR to ISR
The transition is not trivial. The most common issues are:
- Forgotten dependencies on
req/res– ISR has no access to the request object. - Cache‑stale data – unrefreshed data after a database change if
revalidateis too long. - Lack of authorization header handling in the CDN, which prevents serving personalized pages.
The solution is to extract business logic into a service layer (e.g., microservice) and use only pure data in components.
“It’s not about which approach is faster, but which one fits your product’s requirements better.”
Practical Migration Checklist SSR → ISR
- Identify pages that do not need contextual data (session, auth).
- Locate places where you use
req.headers– move them to API routes. - Set a reasonable
revalidateinterval based on data change frequency. - Run performance tests (k6, Artillery) before and after migration.
- Monitor cache misses in Vercel Analytics or your own Prometheus.
Typical Errors and Architectural Trade‑offs
Many teams make the “ISR‑by‑default” mistake, unintentionally serving stale data. The fix is to implement webhooks that trigger unstable_revalidate after every database modification.
Another trade‑off is over‑reliance on CDN cache for dynamic components. In such cases it’s worth splitting part of the UI to client‑side rendering (CSR) while keeping the static skeleton generated by ISR.
In summary, the choice between Next.js Incremental Static Regeneration and SSR should be based on content change frequency, SEO requirements, and projected load. With a conscious caching strategy and proper code segmentation, you can achieve significant cost savings and improve user experience.
If you need help optimizing your Next.js architecture or migrating SSR → ISR, our team at Coderia.it is ready to support your project – contact us today.



