Skip to main content

Command Palette

Search for a command to run...

SSR vs SSG vs ISR - Part 1: The Request (SSR)

How It Works and When to Use

Published
3 min read
SSR vs SSG vs ISR - Part 1: The Request (SSR)

When I started this experiment , I thought SSR was simple:

“SSR renders on every request.”

But when I tried to observe it in practice, something clicked:

All the diagrams in blogs and docs tell you what,
but none tell you why it feels slow or what the browser actually waits for.

So I set up a simple route in my test project:

/pages-ssr   // For Pages Router SSR
/app-ssr     // For App Router SSR

Both do the same thing:

  • simulate an 800 ms delay

  • fetch “data”

  • return a timestamp

  • render a simple UI

Everything else remains constant.

Same UI.
Same data.
Same delay.

Only the rendering strategy changes.

SSR — Not Theory, But What Happens

Here’s what I observed in DevTools:

  1. Open Chrome DevTools → Network

  2. Filter by Doc

  3. Reload /pages-ssr

  4. Click the document request

  5. Go to the Timing tab

  6. Look at Waiting for server response

This is the important part:

You’ll see:

  • Waiting ~800 ms

  • Content download ~negligible

  • Timestamp changes on every refresh

The browser waits until the server is done doing everything — data fetch, render, HTML generation — before it ever gets a byte of HTML.

That’s what SSR really means.

The server is doing work synchronously before responding.
No pre-rendered file.
No caching.
Just work on every request.

In the old blog posts you’d hear:

“SSR increases TTFB.”

But Time to First Byte (TTFB) didn’t become meaningful to me until I saw it in the timing breakdown:

📌 The server doesn’t send HTML until rendering completes.
📌 The browser genuinely waits.
📌 Most of that wait is server compute.

That’s the real mechanism.

Why SSR Isn’t Just a Buzzword

To understand why this matters, consider what SSR promises:

  • Fresh data on every request

And what it costs:

  • You pay the rendering cost each time

  • You pay it before the browser gets HTML

  • That cost shows up as TTFB

In my experiment:

Waiting (TTFB): ~800 ms
Content Download: ~0.5 ms

Look at that green bar in the timing tab. That is total server compute.

No network, no JS. Just server work before response.

That’s SSR.

If you refresh 10 times, the timestamp and timing stay consistent — because every request triggers a new render.

Pages Router vs App Router — Same Outcome, Different API

In the Pages Router, we force SSR using:

export async function getServerSideProps() { … }

In the App Router, we achieve SSR using:

export const dynamic = "force-dynamic";

Different syntax.

Same real behavior.

From the browser’s perspective:

  • HTML is generated per request

  • The timing breakdown is the same

  • TTFB reflects server work before response

The difference is just how Next.js expresses it.

What I Learned About SSR

Here’s the important insight:

SSR is not about React.

SSR is about when HTML is generated.

You can use it when:

  • You must guarantee fresh data every time

  • You cannot cache at any level

  • Every user needs up-to-the-millisecond correctness

But you pay for it by:

  • Blocking the request

  • Increasing TTFB

  • Executing server compute per request

That’s the real SSR execution model — and now we can measure it.


In the next Part, we’ll flip the model completely.

We’ll move the rendering cost out of the request and into the build.

And that change — from per-request to pre-generated — will change everything.