DEV Community

Cover image for Mastering Server‑Side Rendering (SSR)
Md Enayetur Rahman
Md Enayetur Rahman

Posted on

Mastering Server‑Side Rendering (SSR)

“Server‑side rendering is **not* the goal. Faster time‑to‑interactive, better SEO and predictable data is.”*

Learning Patterns, Hallie & Osmani


1. What is Server‑Side Rendering?

Server‑Side Rendering (SSR) means generating the HTML for each request on the server, then sending that markup to the browser so the user sees meaningful UI before JavaScript finishes hydrating.

The sequence is:

  1. Request → browser asks for a page
  2. Render → server executes component tree to HTML
  3. Send → server returns HTML + critical assets
  4. Hydrate → client JavaScript attaches event listeners

SSR differs from Static Site Generation (HTML produced at build time) and purely Client‑Side Rendering (HTML generated after JS loads).


2. Classic React SSR (before frameworks)

npm i express react react-dom react-dom/server
Enter fullscreen mode Exit fullscreen mode
// server.js – minimal SSR with Express
import express from "express";
import { readFileSync } from "fs";
import React from "react";
import { renderToString } from "react-dom/server";
import App from "./App.js";

const htmlTemplate = readFileSync("./index.html", "utf8");
const server = express();

server.get("*", (req, res) => {
  const markup = renderToString(<App url={req.url} />);
  const html = htmlTemplate.replace("<!--app-->", markup);
  res.send(html);
});

server.listen(3000, () => console.log("SSR app ↘ http://localhost:3000"));
Enter fullscreen mode Exit fullscreen mode

This works, but you must hand‑roll routing, code‑splitting, data‑fetch orchestration, streaming, and more.


3. Pros & Cons of SSR

✅ Pros 🚧 Cons
First content paints fast on slow devices Server must render on every request — cost & latency
SEO‑friendly (HTML visible to crawlers) More complicated cache strategy than static generation
Consistent data (no layout shift from client fetching) Adds coupling between server and client environments
Enables progressive streaming & React Suspense Cannot fully leverage CDN edge unless cached

4. SSR with Next.js

Next.js automates bundling, routing, code‑splitting and hot‑reloading while exposing two flavours of SSR:

4.1 Pages Router – getServerSideProps

// pages/index.jsx
export async function getServerSideProps() {
  const res = await fetch("https://api.example.com/posts");
  const posts = await res.json();
  return { props: { posts } };
}

export default function Home({ posts }) {
  return (
    <main>
      <h1>Latest posts</h1>
      <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Every request runs getServerSideProps; HTML streams back to the client.

4.2 App Router (Next 14 +) – Server Components & Streaming

// app/page.tsx (acts like a React Server Component)
import PostList from "./PostList";   // also a server component

export default async function Home() {
  const posts = await fetch("https://api.example.com/posts").then(r => r.json());

  return (
    <>
      <h1>Latest posts</h1>
      {/* PostList can stream in parallel */}
      <PostList initialPosts={posts} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

The App Router uses React Server Components (RSC) and Suspense‐based streaming so HTML chunks arrive progressively.


5. React for the Server (RSC vs SSR)

React 19 stabilised Server Components, letting parts of the tree run only on the server — no JS shipped to the client.

// components/ServerChart.server.jsx
import db from "@/lib/db";
import Chart from "@/components/Chart";   // client component

export default async function ServerChart() {
  const data = await db.sales.findMany();
  return <Chart data={data} />;
}
Enter fullscreen mode Exit fullscreen mode
  • .server.jsx executes on the server, can access secrets, returns serialized props.
  • Client receives just the final HTML for that chunk plus minimal hydration JS for purely interactive children.

This complements SSR: pages can statically stream and embed dynamic server logic.


6. Putting It All Together

  1. Small sites → prefer Static generation; sprinkle RSC for secure data.
  2. Content‑heavy, SEO‑critical apps → SSR via Pages or App router.
  3. Data‑intensive dashboards → mix SSR + RSC + streaming for best TTFB and interactivity.

7. Conclusion

Server‑Side Rendering has matured from hand‑rolled renderToString() scripts to first‑class primitives in Next.js 14 and React 19.

By combining SSR, React Server Components and streaming, you can deliver fast‑painting, SEO‑friendly, user‑centric experiences without drowning in complexity.


Inspired by principles in “Learning Patterns” — Hallie & Osmani, ch. 5 (Rendering Strategies).

Top comments (0)