<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mehrab Hossain</title>
    <description>The latest articles on DEV Community by Mehrab Hossain (@devmehrab).</description>
    <link>https://dev.to/devmehrab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3881035%2F3edf945f-a884-417e-8f1e-448ad04aeb61.jpg</url>
      <title>DEV Community: Mehrab Hossain</title>
      <link>https://dev.to/devmehrab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devmehrab"/>
    <language>en</language>
    <item>
      <title>The Rubber Band That Explains Next.js Rendering (SSR, SSG, ISR, CSR)</title>
      <dc:creator>Mehrab Hossain</dc:creator>
      <pubDate>Wed, 15 Apr 2026 18:50:50 +0000</pubDate>
      <link>https://dev.to/devmehrab/the-rubber-band-that-explains-nextjs-rendering-ssr-ssg-isr-csr-4hoh</link>
      <guid>https://dev.to/devmehrab/the-rubber-band-that-explains-nextjs-rendering-ssr-ssg-isr-csr-4hoh</guid>
      <description>&lt;p&gt;There’s a small trick you can do with a rubber band.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31cdmxsqnnf6e0kilal8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31cdmxsqnnf6e0kilal8.jpg" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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”.&lt;/p&gt;

&lt;p&gt;Nothing fundamental changed.&lt;br&gt;
Same rubber band. Same fingers. Same material.&lt;/p&gt;

&lt;p&gt;Only the arrangement changed.&lt;/p&gt;

&lt;p&gt;That’s exactly how modern Next.js works.&lt;/p&gt;



&lt;p&gt;One Component, Four Realities&lt;/p&gt;

&lt;p&gt;When people first learn Next.js, they often think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSR is one thing&lt;/li&gt;
&lt;li&gt;SSG is another&lt;/li&gt;
&lt;li&gt;ISR is something in between&lt;/li&gt;
&lt;li&gt;CSR is completely different&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that mental model is misleading.&lt;/p&gt;

&lt;p&gt;In reality, you can take one component, make tiny changes, and it behaves like four completely different systems.&lt;/p&gt;

&lt;p&gt;Let’s ground this in something simple: a product listing page.&lt;/p&gt;

&lt;p&gt;You have a component that renders products. Nothing fancy.&lt;/p&gt;

&lt;p&gt;The real question is not what it renders.&lt;/p&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When is the HTML generated?&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;The Hidden Question Behind Everything&lt;/p&gt;

&lt;p&gt;Every rendering strategy in Next.js answers one core question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“When should this page be built?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s walk through the four answers.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Static Site Generation (SSG): Build Once, Serve Forever&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you prepare everything before anyone visits your site.&lt;/p&gt;

&lt;p&gt;At build time, your server fetches product data, generates HTML, and stores it.&lt;/p&gt;

&lt;p&gt;Now when users visit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They don’t trigger computation&lt;/li&gt;
&lt;li&gt;They don’t wait for data fetching&lt;/li&gt;
&lt;li&gt;They just receive ready-made HTML instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s like printing a book in advance instead of writing it every time someone wants to read.&lt;/p&gt;

&lt;p&gt;In App Router, this happens almost silently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.example.com/products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. No special API. No ceremony.&lt;/p&gt;

&lt;p&gt;By default, Next.js assumes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This data probably doesn’t change often. I’ll cache it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That assumption is SSG.&lt;/p&gt;




&lt;p&gt;Incremental Static Regeneration (ISR): Static, But Alive&lt;/p&gt;

&lt;p&gt;Now comes the clever twist.&lt;/p&gt;

&lt;p&gt;What if your product list changes occasionally?&lt;/p&gt;

&lt;p&gt;SSG alone would fail—you’d be stuck with outdated data unless you rebuild the entire app.&lt;/p&gt;

&lt;p&gt;ISR solves this with a simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Serve the static page, but quietly update it in the background.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You add one small instruction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;revalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system behaves differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First request → static page&lt;/li&gt;
&lt;li&gt;Next 10 seconds → same cached page&lt;/li&gt;
&lt;li&gt;After 10 seconds → next request triggers regeneration&lt;/li&gt;
&lt;li&gt;Old page is served while a new one is built&lt;/li&gt;
&lt;li&gt;Cache updates silently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No downtime. No blocking. No full rebuild.&lt;/p&gt;

&lt;p&gt;This is where the rubber band analogy becomes real:&lt;br&gt;
you didn’t replace SSG—you twisted it slightly.&lt;/p&gt;



&lt;p&gt;Server-Side Rendering (SSR): Always Fresh, Always Computed&lt;/p&gt;

&lt;p&gt;Now imagine you don’t trust cached data at all.&lt;/p&gt;

&lt;p&gt;Every request must reflect the latest state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user-specific content&lt;/li&gt;
&lt;li&gt;real-time inventory&lt;/li&gt;
&lt;li&gt;authentication-dependent UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Never cache. Always compute.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hits the server&lt;/li&gt;
&lt;li&gt;Fetches fresh data&lt;/li&gt;
&lt;li&gt;Generates HTML on the fly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is SSR.&lt;/p&gt;

&lt;p&gt;Same component. Same API.&lt;br&gt;
Only one change: cache disabled.&lt;/p&gt;

&lt;p&gt;The rubber band didn’t change shape randomly—you pulled it tighter.&lt;/p&gt;



&lt;p&gt;Client-Side Rendering (CSR): Let the Browser Do the Work&lt;/p&gt;

&lt;p&gt;Now flip the entire model.&lt;/p&gt;

&lt;p&gt;Instead of the server preparing HTML, you send almost nothing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an empty shell&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser loads the page, then fetches data itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(...).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial HTML is empty&lt;/li&gt;
&lt;li&gt;Data loads after page load&lt;/li&gt;
&lt;li&gt;Everything happens in the user’s browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is CSR.&lt;/p&gt;

&lt;p&gt;Not better. Not worse. Just different trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More interactive&lt;/li&gt;
&lt;li&gt;Less SEO-friendly&lt;/li&gt;
&lt;li&gt;Slower initial content&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The Illusion of “Different Systems”&lt;/p&gt;

&lt;p&gt;At first glance, these feel like four completely different architectures.&lt;/p&gt;

&lt;p&gt;But look closer.&lt;/p&gt;

&lt;p&gt;Nothing really changed except:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where code runs (server vs client)&lt;/li&gt;
&lt;li&gt;whether data is cached&lt;/li&gt;
&lt;li&gt;when HTML is generated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it.&lt;/p&gt;




&lt;p&gt;The Real Mechanism: Fetch Controls Everything&lt;/p&gt;

&lt;p&gt;In the App Router world, everything revolves around one primitive:&lt;/p&gt;

&lt;p&gt;fetch(url, options)&lt;/p&gt;

&lt;p&gt;That single line determines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;caching behavior&lt;/li&gt;
&lt;li&gt;rendering strategy&lt;/li&gt;
&lt;li&gt;performance characteristics&lt;/li&gt;
&lt;li&gt;freshness of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re not choosing between “SSR vs SSG” anymore.&lt;/p&gt;

&lt;p&gt;You’re choosing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cache: "force-cache" → SSG&lt;/li&gt;
&lt;li&gt;next.revalidate → ISR&lt;/li&gt;
&lt;li&gt;cache: "no-store" → SSR&lt;/li&gt;
&lt;li&gt;move to client → CSR&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Why ISR Feels Special&lt;/p&gt;

&lt;p&gt;Among the four, ISR often feels the most “magical”.&lt;/p&gt;

&lt;p&gt;That’s because it introduces time into the equation.&lt;/p&gt;

&lt;p&gt;SSG is static.&lt;br&gt;
SSR is immediate.&lt;/p&gt;

&lt;p&gt;ISR says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Stay static… until it makes sense not to.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It blends:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;performance of SSG&lt;/li&gt;
&lt;li&gt;freshness of SSR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it even gives you control beyond time:&lt;/p&gt;

&lt;p&gt;You can trigger updates manually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;after a product is added&lt;/li&gt;
&lt;li&gt;after a CMS update&lt;/li&gt;
&lt;li&gt;via an API endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now your app reacts to events, not just time.&lt;/p&gt;




&lt;p&gt;The Rubber Band Revisited&lt;/p&gt;

&lt;p&gt;Let’s go back to the analogy.&lt;/p&gt;

&lt;p&gt;You didn’t swap tools.&lt;br&gt;
You didn’t rewrite your component.&lt;/p&gt;

&lt;p&gt;You only changed tension and position.&lt;/p&gt;

&lt;p&gt;Rendering| What changed&lt;br&gt;
SSG| Default caching&lt;br&gt;
ISR| Add revalidation&lt;br&gt;
SSR| Disable caching&lt;br&gt;
CSR| Move logic to browser&lt;/p&gt;

&lt;p&gt;Same codebase. Same UI. Same intent.&lt;/p&gt;

&lt;p&gt;Different outcomes.&lt;/p&gt;




&lt;p&gt;The Shift in Thinking&lt;/p&gt;

&lt;p&gt;Most beginners learn Next.js like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“There are four rendering methods. I must choose one.”&lt;br&gt;
That’s outdated thinking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The modern mental model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Rendering is an outcome of caching strategy.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are not picking a mode.&lt;/p&gt;

&lt;p&gt;You are configuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when data is fetched&lt;/li&gt;
&lt;li&gt;how long it lives&lt;/li&gt;
&lt;li&gt;where computation happens&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Why This Matters in Real Projects&lt;/p&gt;

&lt;p&gt;This isn’t just theoretical.&lt;/p&gt;

&lt;p&gt;This is exactly why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your homepage might feel slow (SSR overuse)&lt;/li&gt;
&lt;li&gt;your products might not update (SSG misuse)&lt;/li&gt;
&lt;li&gt;your UI might flicker (CSR overuse)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you understand this model, you stop guessing.&lt;/p&gt;

&lt;p&gt;You start designing.&lt;/p&gt;




&lt;p&gt;Final Thought&lt;/p&gt;

&lt;p&gt;The power of Next.js is not in giving you many APIs.&lt;/p&gt;

&lt;p&gt;It’s in letting you reshape the same system with small, precise changes.&lt;/p&gt;

&lt;p&gt;Like that rubber band.&lt;/p&gt;

&lt;p&gt;At first, it looks like a trick.&lt;/p&gt;

&lt;p&gt;Then you realize—&lt;/p&gt;

&lt;p&gt;it’s just physics.&lt;/p&gt;

&lt;p&gt;And once you understand the tension,&lt;br&gt;
you can make it take any shape you want.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
