IHOR.DEVKNOWLEDGE_BASE
MENU

~/blog / Architecture / static-ssr-or-csr-choose-the-right-rendering-model.md

// pillar guide · 5 min read

Static, SSR, or CSR: Choose the Right Rendering Model

Choose static generation, request-time server rendering, or client rendering per route using freshness, personalization, first-load HTML, and hosting needs.

Quick answer

Static generation produces HTML ahead of a request; SSR produces it while serving a request; CSR builds or updates the interface in the browser. Choose per route, then choose how individual regions update. A public article can start as generated HTML while an interactive search panel runs in the browser. An account page needs request-specific authorization even when most of its layout is shared.

Rendering is separate from caching and from the Server/Client Component boundary. A Server Component can run during a build or a request. A Client Component can contribute to initial server-produced HTML before hydration attaches its event handlers. The presence of use client therefore does not prove that a route is exclusively client-rendered. Keep these three decisions separate when comparing implementations.

Practical implementation steps

1. Specify the first meaningful response

Ask what someone should receive before application JavaScript finishes loading. Product descriptions, article headings, and contact information generally belong in the initial HTML. A private analytics dashboard may tolerate a client loading state, provided its API independently enforces access. Inspect a direct request to each URL, not only navigation from an already running application. This catches routes whose entire visible content depends on a browser-only fetch.

2. Assign freshness and personalization separately

A frequently changing public page can still use controlled cache revalidation. A rarely changing private record still requires authorization. For every data source, name the acceptable stale interval and whether its output differs by user. Do not put personalized HTML in a shared cache. Conversely, reading a session in the top-level layout may unnecessarily force public content onto a request-time path.

3. Confirm the deployment contract

A static export has no application server available when a visitor arrives. Generate dynamic-path parameters during the build and use an external API for request-time operations. SSR needs a compatible runtime and must handle backend outages while responding. A client app needs correct deep-link fallback and cache headers for its assets. These are deployment requirements, not reasons to rank one rendering model as universally faster.

Implementation example

This Next.js example uses the model without Cache Components, consistent with this repository’s configuration. It generates known article paths at build time. The local entries are deliberately tiny illustrative data. A production content system also needs validation and an explicit decision about missing or newly published slugs; exporting files cannot create an unknown route at request time.

// app/articles/[slug]/page.tsx
import { notFound } from "next/navigation";

const articles = [
  { slug: "rendering", title: "Rendering choices", body: "Start with the route." },
];

export function generateStaticParams() {
  return articles.map(({ slug }) => ({ slug }));
}

export default async function Page({
  params,
}: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const article = articles.find((entry) => entry.slug === slug);
  if (!article) notFound();
  return <article><h1>{article.title}</h1><p>{article.body}</p></article>;
}

Request-time account data would follow a different path with a verified session and an authorized server read. Browser filtering could be added as a small Client Component receiving only public article fields. Neither change requires the whole site to adopt a single rendering mode. Treat each boundary as a deliberate answer to the data it owns.

Tradeoffs and alternatives

Generated HTML reduces request-time dependencies but introduces publication and invalidation work. SSR can personalize the first response but makes backend latency part of page delivery. CSR enables rich interaction and client-owned state, while a slow initial bundle or sequential API calls can delay meaningful content. Measure representative pages with realistic payloads and a cold browser cache; labels alone cannot predict the outcome.

Common mistakes

Confusing RSC with SSR leads teams to assume an async component always runs for each visitor. Confusing client components with CSR leads them to access window during prerendering. A third failure is testing only client navigation: direct links may return an empty shell, incorrect status, or hosting error. Finally, generating a price at build time does not make it authoritative when checkout accepts an order.

Production checklist

  • Direct URLs return the expected HTML and status.
  • Public and personalized output use separate cache policies.
  • Freshness requirements name an update or revalidation path.
  • Unknown routes produce the intended not-found response.
  • Browser interaction survives slow or failed data requests.
  • The host supports every request-time feature used.

FAQ

Can a static site include forms?

Yes, if submission reaches a separate server or service that validates and stores it. Static hosting alone cannot execute a Server Action. Make success depend on the receiving system’s acceptance, rather than on a client animation or an unverified email delivery assumption.

Does SSR guarantee indexing?

No. Rendering determines what is delivered; discovery, indexability, canonical signals, content quality, and search-engine processing remain separate. Delivering useful initial HTML makes it easier to inspect content and links, but it is not a promise that a search engine will index or rank the page.

Next step

Create a route matrix with initial HTML, personalization, freshness, and deployment mode. Implement the most constrained route first, then inspect direct loading and navigation. Change rendering only when that evidence exposes a problem; an interactive widget does not by itself justify replacing generated public pages with request-time rendering.

Primary sources

Ihor Kharchyshyn

Independent full-stack product engineer writing source-backed implementation guides for browser extensions and modern web products.

Need this implemented in a real product?

Explore relevant product case studies or share the context for a web application, Chrome extension, API, or SaaS build.