Skip to content
Now accepting Q2 projects — limited slots available. Get started →
Architecture · Updated Apr 30, 2026

What is Server-Side Rendering (SSR)?

Server-Side Rendering (SSR) is a web architecture pattern that generates HTML on the server for each incoming request.

What is Server-Side Rendering (SSR)?

Server-Side Rendering (SSR) is a web architecture pattern where the server generates the full HTML for a page on every incoming request, then sends that markup to the browser. Unlike client-side rendering (CSR), where the browser downloads a JavaScript bundle and builds the DOM locally, SSR delivers a complete document that's immediately parseable by search engines and screen readers. The technique predates the SPA era — traditional PHP, Rails, and Django apps were SSR by default — but it became a distinct architectural choice again around 2016 when Next.js (v1, October 2016) reintroduced it for React apps. SSR typically improves Largest Contentful Paint (LCP) because the browser paints meaningful content before any JS executes. The trade-off is higher server compute per request compared to pre-built static pages. We reach for SSR on projects where content depends on the request — authenticated dashboards, personalized storefronts, or pages with real-time data that can't be statically generated at build time.

How it works

When a user (or a bot) requests a URL, the SSR server runs the page's component tree, fetches any required data, and produces an HTML string. That string is sent as the HTTP response with a Content-Type: text/html header. Here's a simplified Next.js App Router example:

// app/products/[slug]/page.tsx
export const dynamic = 'force-dynamic'; // opt into SSR

export default async function ProductPage({ params }: { params: { slug: string } }) {
  const product = await fetch(`https://api.example.com/products/${params.slug}`, {
    cache: 'no-store',
  }).then(res => res.json());

  return (
    <main>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <span>${product.price}</span>
    </main>
  );
}

The cache: 'no-store' directive tells Next.js (v14+/v15) not to cache the fetch, so data is fresh on every request. After the HTML arrives, the browser downloads the JS bundle and hydrates the page — attaching event listeners and making it interactive. In Astro (v4+), SSR is enabled by setting output: 'server' in astro.config.mjs, and components only ship JS if you explicitly add a client:* directive, which keeps the hydration payload small.

On the infrastructure side, SSR requires a running server or serverless function (AWS Lambda, Vercel Functions, Cloudflare Workers). Response times depend on data-fetch latency and render complexity. Techniques like streaming SSR (React 18's renderToPipeableStream) let the server flush HTML in chunks, so the browser can start painting before the full response completes — this measurably improves Time to First Byte (TTFB) on data-heavy pages.

When to use it

SSR is the right call when the HTML must reflect request-specific data that can't be known at build time. Concrete scenarios:

  • Yes: Authenticated pages (dashboards, account settings) where content varies per user session.

  • Yes: E-commerce product pages with real-time inventory or pricing pulled from a headless CMS or PIM.

  • Yes: Search results pages where query params drive the content and you still need crawlable HTML.

  • Yes: Pages behind A/B tests that need different markup per visitor without client-side flicker.

  • No: Marketing pages, blog posts, docs — use Static Site Generation (SSG) or Incremental Static Regeneration (ISR) instead. Faster, cheaper, cacheable at the CDN edge.

  • No: Highly interactive apps (spreadsheets, design tools) where the initial HTML shell is trivial — CSR with a loading skeleton is often simpler.

  • No: When your data changes less than once per minute and you can tolerate stale-while-revalidate — ISR gives SSR-like freshness without per-request compute.

We've shipped SSR on 50+ projects. Our rule of thumb: if you can statically generate it, do. SSR is for the pages that truly can't be.

SSR vs alternatives

Criteria SSR SSG / ISR CSR (SPA) Edge SSR
HTML generated Per request, on server At build time (or revalidated) In browser Per request, at edge
TTFB Medium (server + data fetch) Fast (CDN-cached) Fast (small shell) Fast (close to user)
LCP Good Excellent Poor without prerender Good
SEO friendliness Excellent Excellent Weak without prerender Excellent
Server cost Higher (compute per req) Low (static files) None (client only) Medium (edge compute)
Data freshness Real-time Stale until rebuild/revalidate Real-time (client fetch) Real-time

Edge SSR (Cloudflare Workers, Vercel Edge Functions) is a hybrid: it runs SSR logic on edge nodes closer to users, reducing TTFB. The constraint is runtime — you're limited to V8 isolates, no Node.js APIs. Our preferred stack is Next.js 15 on Vercel with edge middleware for auth checks and Node.js SSR for data-heavy pages.

Real-world example

We built a headless Shopify storefront for a DTC brand using Next.js 15 App Router. Product listing pages used ISR with a 60-second revalidation window — good enough for SEO, low compute cost. But the cart page and checkout flow required SSR because they depended on session cookies and real-time inventory checks from Shopify's Storefront API. After switching those routes from CSR to SSR, the cart page's LCP dropped from ~3.2s to ~1.4s on mobile (measured via CrUX data over 28 days). Googlebot indexed the cart-adjacent pages correctly for the first time, and the brand saw a 12% lift in organic landing page impressions for transactional queries. Astro would've been a solid choice here too, but the team already had React expertise, so Next.js was the pragmatic pick.

Frequently asked questions about Server-Side Rendering (SSR)

Is Server-Side Rendering the same as Static Site Generation?
No. SSR generates HTML on the server at request time — every visit triggers a render. Static Site Generation (SSG) generates HTML at build time, producing flat files that are served from a CDN with no per-request compute. ISR (Incremental Static Regeneration) is a middle ground: pages are statically generated but revalidated on a timer or on-demand. Use SSG when content doesn't change per request; use SSR when it does. In Next.js, the distinction comes down to caching directives — `force-dynamic` for SSR, `force-static` or time-based `revalidate` for SSG/ISR.
When did Server-Side Rendering become standard in modern JavaScript frameworks?
SSR has always been the default in traditional server frameworks (PHP, Rails, Django). In the JavaScript ecosystem, it became a first-class pattern again with Next.js v1 in October 2016 and Nuxt.js v1 in January 2018. React 16 (September 2017) improved `renderToString` performance significantly, and React 18 (March 2022) introduced streaming SSR via `renderToPipeableStream`, which was a major milestone. By 2024, SSR was a standard option in Next.js, Nuxt, SvelteKit, Astro, Remix, and SolidStart. It's no longer novel — it's just one rendering strategy you pick based on the page's data requirements.
What's the alternative to Server-Side Rendering?
The main alternatives are Static Site Generation (SSG), Client-Side Rendering (CSR), and Edge SSR. SSG pre-builds HTML at deploy time — fastest TTFB, lowest cost, but content is stale until the next build or revalidation. CSR sends a minimal HTML shell and lets JavaScript render everything in the browser — simple to deploy (just static files) but poor for SEO and initial load performance. Edge SSR runs the same server-render logic but on edge nodes (Cloudflare Workers, Deno Deploy), reducing latency. Many real-world apps mix strategies: SSG for marketing pages, SSR for authenticated routes, CSR for highly interactive widgets.
Does Server-Side Rendering hurt performance compared to static pages?
It can. SSR adds server processing time to every request — your TTFB depends on how long data fetches and rendering take. A static page served from a CDN edge might have a TTFB under 50ms, while an SSR page hitting a database could take 200-800ms. Streaming SSR mitigates this by flushing partial HTML early, so the browser starts painting before the full response arrives. Caching strategies help too: you can cache SSR responses at the CDN with short TTLs (e.g., `Cache-Control: s-maxage=10, stale-while-revalidate=59`). The performance trade-off is real, but for pages that need fresh, per-request data, SSR still delivers better LCP and SEO than CSR.
Get in touch

Let's build
something together.

Whether it's a migration, a new build, or an SEO challenge — the Social Animal team would love to hear from you.

Get in touch →