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

When I started this [experiment](https://github.com/akanandhu/SSRxSSGxISR) , 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:

```plaintext
/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:

![](https://cdn.hashnode.com/uploads/covers/65ec0b64d124c1c86ca0fb08/d2c2a27a-3f88-4f78-b0c6-31e1b516476e.png align="center")

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:

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

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

![](https://cdn.hashnode.com/uploads/covers/65ec0b64d124c1c86ca0fb08/8160e9f8-276a-4f10-b3c4-a4939f078345.png align="center")

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:

```javascript
export async function getServerSideProps() { … }
```

In the App Router, we achieve SSR using:

```javascript
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.
