Server-Side Rendering (SSR)
Understand Server-Side Rendering in Next.js — when to use it, how it works with the App Router, and how to avoid the performance traps that catch most developers.
Last reviewed: January 2025
🔍 What Is It?
Server-Side Rendering (SSR) generates a fresh HTML response for every incoming request. In Next.js App Router:
- →A route is dynamic (SSR) when it accesses request-specific data:
cookies(),headers(),searchParams, or usesfetchwithcache: 'no-store' - →A route is static (SSG) when it has no request-specific dependencies
- →Next.js automatically detects which mode to use — no explicit configuration needed
SSR is the right choice when:
- →Content is user-specific (logged-in user's dashboard)
- →Content changes frequently and must be fresh on every request
- →You need access to request cookies/headers (auth sessions)
- →Real-time data that cannot be stale even for 1 second
🎯 Why Do We Need It?
Static pages are faster but cannot serve personalised content. SSR bridges the gap:
- →Authentication — serve different content based on the user's session
- →Personalisation — show user-specific data, preferences, recommendations
- →Real-time accuracy — stock prices, live inventory, breaking news
- →A/B testing — serve different variants based on cookies
Without SSR, you'd either serve the same page to everyone (wrong) or fetch personalised data client-side (slow, bad UX, bad SEO).
🏗️ What Happens in Real Projects?
SSR routes in a real enterprise app:
- →
/dashboard— reads session cookie, fetches user-specific metrics - →
/checkout— reads cart from session, checks real-time inventory - →
/search?q=...— reads searchParams, returns personalised results - →
/account/orders— reads auth cookie, fetches user's orders
Static routes in the same app:
- →
/products— same for all users, revalidated every hour (ISR) - →
/blog/[slug]— pre-built at deploy time (SSG) - →
/about,/pricing— pure static HTML
⚙️ How It Works
SSR request lifecycle in App Router:
- Request hits the server with a cookie
session=abc123 - Next.js identifies the route as dynamic (it reads cookies)
- The Server Component runs:
const session = await getSession() - Data is fetched based on the session:
await db.query(userId) - HTML is rendered and streamed to the browser
- The browser displays the HTML — no loading spinner for the initial content
- Client Components hydrate for interactivity
Opting into dynamic rendering:
import { cookies } from 'next/headers';
export default async function Page() {
const cookieStore = await cookies(); // This makes the route dynamic
const token = cookieStore.get('token');
// ...
}💻 Example
SSR Patterns in Next.js 14 — Dynamic routes that correctly handle authentication and personalisation.
🤔 Common Confusions
❓ How do I opt into SSR in the App Router?
You do not opt in explicitly — Next.js detects it automatically. Use cookies(), headers(), or searchParams, or set cache: "no-store" on a fetch call. The route becomes dynamic automatically. You can also set export const dynamic = "force-dynamic" at the top of a page file.
❓ Is SSR in the App Router the same as getServerSideProps?
Functionally yes — HTML is generated per request. But the implementation is completely different. Instead of a separate getServerSideProps function, you use async Server Components that read cookies/headers. The result is the same: fresh HTML per request.
❓ Does SSR hurt performance?
SSR adds server processing time per request, but it eliminates the client-side loading waterfall. For users, SSR often feels faster because they see content immediately instead of a loading spinner. The tradeoff: server CPU cost vs client loading time. For personalised content, SSR is almost always the right choice.
🚨 Common Production Issues
Accidentally making static routes dynamic — importing cookies() or headers() anywhere in the component tree makes the entire route dynamic, even if you do not use the value. Only import them when you actually need them.
SSR without caching under load — a high-traffic SSR route that queries the DB on every request will overwhelm your database. Add Redis caching or use unstable_cache to cache the DB results for a few seconds.
Slow TTFB (Time To First Byte) — if your SSR data fetching is slow, users wait for the first byte of HTML. Use streaming (Suspense) to send the page shell immediately and stream in the data-dependent parts.
✅ Best Practices
Use SSR only when content is genuinely request-specific — prefer ISR for content that changes infrequently
Cache DB queries in SSR routes with unstable_cache or Redis — do not hit the DB on every request
Use streaming to send the page shell immediately while data loads
Set explicit cache headers on SSR responses — even dynamic pages can be cached at the CDN for a few seconds
Profile your SSR routes with next build and server timing headers to find slow data fetches
🏛️ Architect's Note
A common architectural mistake is defaulting everything to SSR. SSR has a real cost: every request hits your server and often your database. The right architecture uses SSR only where necessary and pushes everything else to static (SSG/ISR).
The decision tree: Is the content the same for all users? → SSG/ISR. Does it change frequently? → ISR with short revalidation. Is it user-specific? → SSR. Can it be fetched client-side after initial load? → Static shell + client fetch.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
↗ Where this topic fits
Next.js Technology Guide
Return to the Next.js learning hub.
Frontend Engineer Career Path
A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Next.js references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Next.js learning path
Browse the full Next.js topic collection and learning order on SplashRide.
Next.js Interview Prep
Practice Next.js interview questions and scenario-based answers.
Frontend Engineer Career Path
A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Static Site Generation (SSG)
Master Static Site Generation in Next.js — pre-building pages at deploy time for maximum performance, CDN delivery, and zero server costs.
Incremental Static Regeneration (ISR)
Master ISR — the Next.js feature that gives you static performance with dynamic freshness. Learn time-based and on-demand revalidation for real production systems.