Skip to content
SP StackPractices
intermediate By StackPractices

Server-Side Rendering

Improve performance and SEO with server-side rendering using Next.js, Nuxt, Astro, and other frameworks with hydration strategies.

Topics: frontend

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

Server-side rendering (SSR) generates HTML on the server for each request, sending a fully rendered page to the browser. This improves initial page load, SEO, and social sharing previews. Modern frameworks like Next.js, Nuxt, and Astro combine SSR with client-side hydration to deliver fast first paints and interactive experiences without sacrificing crawlability.

When to Use

Use this resource when:

  • Building content-heavy sites that rely on search engine indexing
  • Social sharing requires accurate Open Graph previews
  • Users on slow networks need meaningful content immediately
  • JavaScript-heavy SPAs have poor Core Web Vitals scores

Solution

Next.js App Router with Streaming SSR

// app/page.tsx
async function getProducts() {
  const res = await fetch('https://api.example.com/products', {
    next: { revalidate: 60 }
  });
  return res.json();
}

export default async function ProductsPage() {
  const products = await getProducts();

  return (
    <main>
      <h1>Products</h1>
      <ul>
        {products.map(p => (
          <li key={p.id}>{p.name} — ${p.price}</li>
        ))}
      </ul>
    </main>
  );
}

Astro Islands Architecture

---
// Server-rendered at build time or on request
const response = await fetch('https://api.example.com/stats');
const stats = await response.json();
---

<html>
  <body>
    <h1>Dashboard</h1>
    <!-- Static, server-rendered HTML -->
    <p>Total Users: {stats.users}</p>

    <!-- Interactive island hydrates on client -->
    <LiveChart client:load data={stats.chart} />
  </body>
</html>

Nuxt 3 SSR with Hybrid Rendering

<script setup>
const { data: posts } = await useFetch('/api/posts', {
  server: true,   // Render on server
  default: () => []
});
</script>

<template>
  <div>
    <h1>Blog</h1>
    <article v-for="post in posts" :key="post.id">
      <h2>{{ post.title }}</h2>
      <p>{{ post.excerpt }}</p>
    </article>
  </div>
</template>

Explanation

How hydration works:

  1. Server renders complete HTML and sends to browser
  2. Browser displays content immediately (fast LCP)
  3. JavaScript bundle loads and “hydrates” the page
  4. Event listeners attach; components become interactive

SSR vs. SSG vs. CSR:

StrategyRender TimeUse Case
SSRPer requestDynamic data; personalized content
SSGBuild timeStatic content; maximum cacheability
CSRClient sideHighly interactive dashboards; SPAs
ISRHybridNews sites; product catalogs

Variants

FrameworkApproachNotable
Next.jsSSR + SSG + ISRReact; Vercel optimization
NuxtSSR + SSGVue; file-based routing
AstroIslandsZero JS by default; partial hydration
SvelteKitSSR + CSRSvelte; edge-ready
RemixSSR + progressive enhancementForms work without JS

Best Practices

  • Use streaming for slow data: Suspense boundaries let critical UI render while data loads
  • Avoid hydration mismatches: Server and client HTML must match exactly
  • Serialize minimal state: Only pass data the client needs; avoid full database dumps
  • Cache SSR responses: CDN caching with stale-while-revalidate reduces server load
  • Lazy-load below-fold: Use client:visible (Astro) or dynamic imports for non-critical interactivity

Common Mistakes

  1. Hydrating everything: Not every component needs to be interactive; islands architecture saves JS
  2. Blocking on slow APIs: A 5-second database query delays the entire page; use streaming
  3. Ignoring memory leaks: Each SSR request creates new component instances; clean up subscriptions
  4. No error boundaries: SSR crashes should return a degraded static page, not a 500
  5. Over-caching dynamic content: SSG caching personalized dashboards shows wrong data to wrong users

Frequently Asked Questions

Q: Does SSR hurt performance? A: It improves initial load but adds server cost. Use SSG or ISR for content that doesn’t change per user.

Q: Can I use SSR with a headless CMS? A: Yes. Fetch CMS data during SSR; the CMS only serves the API, not the rendered page.

Q: What’s the difference between SSR and hydration? A: SSR produces HTML on the server. Hydration makes that static HTML interactive on the client.