DEV Community

Mehrab Hossain
Mehrab Hossain

Posted on

The Rubber Band That Explains Next.js Rendering (SSR, SSG, ISR, CSR)

There’s a small trick you can do with a rubber band.

You stretch it between your fingers, twist it in a certain way—and suddenly it forms a star. A slight adjustment, just a tiny shift in tension, and now it resembles the Eiffel Tower. Another small move, and it becomes the letter “X”.

Nothing fundamental changed.
Same rubber band. Same fingers. Same material.

Only the arrangement changed.

That’s exactly how modern Next.js works.


One Component, Four Realities

When people first learn Next.js, they often think:

  • SSR is one thing
  • SSG is another
  • ISR is something in between
  • CSR is completely different

But that mental model is misleading.

In reality, you can take one component, make tiny changes, and it behaves like four completely different systems.

Let’s ground this in something simple: a product listing page.

You have a component that renders products. Nothing fancy.

The real question is not what it renders.

The real question is:

When is the HTML generated?


The Hidden Question Behind Everything

Every rendering strategy in Next.js answers one core question:

“When should this page be built?”

Let’s walk through the four answers.


Static Site Generation (SSG): Build Once, Serve Forever

Imagine you prepare everything before anyone visits your site.

At build time, your server fetches product data, generates HTML, and stores it.

Now when users visit:

  • They don’t trigger computation
  • They don’t wait for data fetching
  • They just receive ready-made HTML instantly

It’s like printing a book in advance instead of writing it every time someone wants to read.

In App Router, this happens almost silently:

await fetch("https://api.example.com/products");
Enter fullscreen mode Exit fullscreen mode

That’s it. No special API. No ceremony.

By default, Next.js assumes:

“This data probably doesn’t change often. I’ll cache it.”

That assumption is SSG.


Incremental Static Regeneration (ISR): Static, But Alive

Now comes the clever twist.

What if your product list changes occasionally?

SSG alone would fail—you’d be stuck with outdated data unless you rebuild the entire app.

ISR solves this with a simple idea:

“Serve the static page, but quietly update it in the background.”

You add one small instruction:

fetch(url, {
  next: { revalidate: 10 }
});
Enter fullscreen mode Exit fullscreen mode

Now the system behaves differently:

  • First request → static page
  • Next 10 seconds → same cached page
  • After 10 seconds → next request triggers regeneration
  • Old page is served while a new one is built
  • Cache updates silently

No downtime. No blocking. No full rebuild.

This is where the rubber band analogy becomes real:
you didn’t replace SSG—you twisted it slightly.


Server-Side Rendering (SSR): Always Fresh, Always Computed

Now imagine you don’t trust cached data at all.

Every request must reflect the latest state:

  • user-specific content
  • real-time inventory
  • authentication-dependent UI

So you say:

“Never cache. Always compute.”

That’s one line:

fetch(url, {
  cache: "no-store"
});
Enter fullscreen mode Exit fullscreen mode

Now every request:

  • Hits the server
  • Fetches fresh data
  • Generates HTML on the fly

This is SSR.

Same component. Same API.
Only one change: cache disabled.

The rubber band didn’t change shape randomly—you pulled it tighter.


Client-Side Rendering (CSR): Let the Browser Do the Work

Now flip the entire model.

Instead of the server preparing HTML, you send almost nothing:

  • an empty shell
  • JavaScript
  • instructions

The browser loads the page, then fetches data itself.

"use client";

useEffect(() => {
  fetch(...).then(setData);
}, []);
Enter fullscreen mode Exit fullscreen mode

Now:

  • Initial HTML is empty
  • Data loads after page load
  • Everything happens in the user’s browser

This is CSR.

Not better. Not worse. Just different trade-offs:

  • More interactive
  • Less SEO-friendly
  • Slower initial content

The Illusion of “Different Systems”

At first glance, these feel like four completely different architectures.

But look closer.

Nothing really changed except:

  • where code runs (server vs client)
  • whether data is cached
  • when HTML is generated

That’s it.


The Real Mechanism: Fetch Controls Everything

In the App Router world, everything revolves around one primitive:

fetch(url, options)

That single line determines:

  • caching behavior
  • rendering strategy
  • performance characteristics
  • freshness of data

You’re not choosing between “SSR vs SSG” anymore.

You’re choosing:

  • cache: "force-cache" → SSG
  • next.revalidate → ISR
  • cache: "no-store" → SSR
  • move to client → CSR

Why ISR Feels Special

Among the four, ISR often feels the most “magical”.

That’s because it introduces time into the equation.

SSG is static.
SSR is immediate.

ISR says:

“Stay static… until it makes sense not to.”

It blends:

  • performance of SSG
  • freshness of SSR

And it even gives you control beyond time:

You can trigger updates manually:

  • after a product is added
  • after a CMS update
  • via an API endpoint

Now your app reacts to events, not just time.


The Rubber Band Revisited

Let’s go back to the analogy.

You didn’t swap tools.
You didn’t rewrite your component.

You only changed tension and position.

Rendering| What changed
SSG| Default caching
ISR| Add revalidation
SSR| Disable caching
CSR| Move logic to browser

Same codebase. Same UI. Same intent.

Different outcomes.


The Shift in Thinking

Most beginners learn Next.js like this:

“There are four rendering methods. I must choose one.”
That’s outdated thinking.

The modern mental model is:

“Rendering is an outcome of caching strategy.”

You are not picking a mode.

You are configuring:

  • when data is fetched
  • how long it lives
  • where computation happens

Why This Matters in Real Projects

This isn’t just theoretical.

This is exactly why:

  • your homepage might feel slow (SSR overuse)
  • your products might not update (SSG misuse)
  • your UI might flicker (CSR overuse)

Once you understand this model, you stop guessing.

You start designing.


Final Thought

The power of Next.js is not in giving you many APIs.

It’s in letting you reshape the same system with small, precise changes.

Like that rubber band.

At first, it looks like a trick.

Then you realize—

it’s just physics.

And once you understand the tension,
you can make it take any shape you want.

Top comments (0)