Switched to SSR When “Good Enough” Started Causing Real Problems - Pt 4
Series: Part 4 of Rendering with Intent
Breaking down how I learned to choose rendering strategies intentionally rather than relying on defaults.
Static rendering worked for content that rarely changed. ISR handled fresh-but-not-immediate pages. But some parts of WonderBook couldn’t be cached or prebuilt at all, they had to be evaluated per user, per request, every time.
That’s when I turned to SSR (Server-Side Rendering).
How SSR works
SSR generates HTML at request time using live data, not a cached copy. Each visitor gets a page rendered specifically for them, with fresh database queries and user context baked into the HTML before it’s sent.
This guarantees that the user sees up-to-date data, but at the cost of caching efficiency.
When SSR makes sense
| ✅ Use SSR when | ❌ Avoid SSR when |
|---|---|
| Data depends on the user | Content is static |
| Page requires authentication | Data changes rarely |
| Security or privacy matters | Speed is the top priority |
| Real-time accuracy is critical | SEO is the main goal without dynamic data |
SSR trades cached speed for correctness and security. It’s about trust: ensuring what’s displayed is exactly true in that moment for that user.
Why SSR can feel slower. TTFB and rendering cost
SSR doesn’t just render on demand, it waits until a user asks. That extra computation time shows up as TTFB (Time To First Byte), which is how long it takes for the browser to start receiving the first byte of HTML from the server.
Here’s how different rendering strategies typically impact TTFB:
| Rendering Strategy | TTFB Impact | Why |
|---|---|---|
| Static (SSG/ISR prebuilt) | Very low | Already rendered and served instantly from a CDN |
| ISR (after regen) | Low | Acts like static once cached |
| SSR | High | Server fetches data and renders fresh HTML per request |
| Client-side rendering | Low TTFB but slower to become useful | HTML arrives quickly, but content isn’t interactive until JS runs |
| Streaming | Medium TTFB but feels faster | Server sends partial HTML progressively so users see something sooner |
SSR isn't bad because it's slower. It’s slower because it’s doing real work in real time, and that work only makes sense when correctness outweighs latency.
SSR in WonderBook - Dashboard
The user dashboard shows generated stories, word counts, and AI credit balances. It’s personalised, authenticated, and constantly changing. Caching it would risk showing the wrong data to the wrong user.
export const dynamic = "force-dynamic"; export default async function DashboardPage() { const user = await getUser(); const stories = await getUserStories(user.id); return <Dashboard stories={stories} />; }
In case you missed the other posts, here they are:
The Rendering with Intent Series
- Part 1: Rendering Blindly Cost Me Speed, Money, and Sanity. Here’s How I Fixed It
- Part 2: Static Rendering. Doing the Work Before Anyone Asks For It
- Part 3: I Wanted Static Speed Without Serving Yesterday’s Data. ISR Was the Answer
- Part 4: Switched to SSR When “Good Enough” Started Causing Real Problems [You are here]
- Part 5: When Static Pages Weren’t Enough, Client Components Took Over
- Part 6: I Made Data Feel Faster Without Actually Speeding It Up