Jour 31 Day 31 · mercredi 16 septembre 2026 Wednesday 16 September 2026 Web Intermédiaire
SSR, CSR, SSG & hydration SSR, CSR, SSG & hydration
Où le HTML est-il produit, quand, et à quel prix ? La question de rendu web revient dans tous les entretiens front — savoir justifier CSR vs SSR vs SSG vs ISR selon le produit fait la différence. Where is the HTML produced, when, and at what cost? The web rendering question comes up in every frontend interview — being able to justify CSR vs SSR vs SSG vs ISR per product makes the difference.
L’essentiel
Toute la question du rendu web tient en une phrase : où et quand le HTML est-il produit ? Quatre réponses possibles, quatre stratégies :
| CSR | SSR | SSG | ISR | |
|---|---|---|---|---|
| HTML produit | Navigateur (JS) | Serveur, par requête | Build, une fois | Build + régénération |
| TTFB | Rapide (coquille vide) | Plus lent (calcul) | Excellent (statique) | Excellent (statique) |
| Contenu initial | Vide puis fetch | Complet | Complet | Complet |
| SEO | Fragile | Bon | Bon | Bon |
| Fraîcheur données | Temps réel | Par requête | Figée au build | Périodique |
| Coût serveur | Quasi nul (CDN) | Un rendu/requête | Quasi nul (CDN) | Faible |
| Exemple type | Dashboard, SaaS | E-commerce, feed | Docs, blog, portfolio | Catalogue, presse |
- CSR (Client-Side Rendering) : le serveur envoie une page quasi vide + un bundle JS ; le navigateur télécharge, exécute, fetch les données, et construit le DOM. C’est le modèle SPA (React avec Vite, par exemple).
- SSR (Server-Side Rendering) : le serveur exécute les composants à chaque requête et renvoie du HTML complet. L’utilisateur voit le contenu tout de suite… mais il n’est pas encore interactif (voir hydration).
- SSG (Static Site Generation) : le HTML est généré au build, une fois pour toutes, puis servi tel quel depuis un CDN. Imbattable en perf et en coût — tant que le contenu ne change pas à chaque requête.
- ISR (Incremental Static Regeneration) : du SSG dont les pages se régénèrent en arrière-plan après expiration d’un délai (
revalidate). Le beurre du statique, l’argent de la fraîcheur.
Comment ça marche
Le point que les candidats ratent le plus : le HTML rendu côté serveur n’est pas interactif. Les gestionnaires d’événements (onClick…) n’existent que dans le JS. Il faut donc l’hydration : le navigateur télécharge le bundle, ré-exécute les composants, fait correspondre le résultat au DOM existant, et attache les événements. Entre le premier affichage et la fin de l’hydration, la page est visible mais sourde — cliquer ne fait rien.
SSR + hydration, chronologie :
t0 ── requête ──▶ serveur rend le HTML
t1 ◀── HTML complet ── FCP : l'utilisateur VOIT la page
t2 ◀── bundle JS ──── téléchargement + parsing
t3 ─── hydration ──── React ré-exécute et attache
t4 ─── TTI ────────── la page RÉPOND aux clics
t1 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ t4
"uncanny valley" : visible
mais pas interactive
En CSR, la timeline est inversée : rien à voir avant t3, mais dès que ça s’affiche, c’est interactif. Le SSR optimise le First Contentful Paint, pas le Time To Interactive.
Deux évolutions attaquent ce coût d’hydration :
- Islands architecture (Astro) : la page est du HTML statique par défaut, et seuls quelques îlots explicitement marqués interactifs (
client:load,client:visible) reçoivent du JS. Le site sur lequel vous lisez cette fiche fonctionne exactement comme ça : le contenu est statique, le quiz est un îlot. Zéro JS pour le texte, un petit bundle pour l’interactif. - Streaming SSR & Server Components (survol) : plutôt que d’attendre que toute la page soit prête, le serveur streame le HTML par morceaux (
<Suspense>), et les React Server Components ne s’hydratent jamais — leur code ne quitte pas le serveur, seul le résultat voyage. Moins de JS envoyé, hydration sélective.
🎤 En entretien — « pourquoi ton site perso est en SSG ? » La meilleure réponse relie stratégie et produit : « le contenu change quand je le décide (au déploiement), pas à chaque visite. Donc je paie le rendu une fois au build, je sers du HTML pur depuis un CDN : TTFB minimal, SEO parfait, hébergement gratuit, rien à sécuriser côté serveur. Du SSR serait payer à chaque requête pour recalculer un résultat identique. » Vous venez de montrer que vous choisissez une architecture par ses trade-offs, pas par la hype.
Concepts clés à maîtriser
- Choisir selon le produit, pas la mode : contenu identique pour tous et rarement modifié → SSG. Contenu par utilisateur ou changeant à chaque requête + SEO → SSR. App derrière un login, sans enjeu SEO → CSR suffit largement. Catalogue volumineux mis à jour périodiquement → ISR.
- SEO et crawlers : Google exécute le JS, mais avec délai et budget de crawl ; les aperçus de liens (Slack, réseaux sociaux) ne l’exécutent pas du tout. Un contenu qui doit être indexé ou partagé doit être dans le HTML initial.
- Hydration mismatch : si le rendu client ne correspond pas au HTML serveur (date
new Date(),Math.random(),window.innerWidth…), le framework avertit et re-rend — flash visuel et perf dégradée. Règle : le premier rendu doit être déterministe, les valeurs client-only arrivent dans unuseEffect. - Le mix par route : les frameworks modernes (Next.js, Nuxt, SvelteKit) choisissent la stratégie page par page — landing en SSG, produit en ISR, panier en SSR ou CSR. « Quel rendu pour ce site ? » est une question par route, pas globale.
L’exemple canonique de SSG paramétré, getStaticPaths :
// pages/blog/[slug].jsx — Next.js (Pages Router)
// Au BUILD : quelles pages générer ?
export async function getStaticPaths() {
const posts = await cms.getAllPosts();
return {
paths: posts.map((p) => ({ params: { slug: p.slug } })),
fallback: "blocking", // slug inconnu → rendu à la volée puis mis en cache
};
}
// Au BUILD, pour chaque slug : les données de la page
export async function getStaticProps({ params }) {
const post = await cms.getPost(params.slug);
if (!post) return { notFound: true };
return {
props: { post },
revalidate: 3600, // ISR : régénérée en arrière-plan au plus toutes les heures
};
}
// Ce composant s'exécute au build (et à l'hydration côté client)
export default function BlogPost({ post }) {
return <article dangerouslySetInnerHTML={{ __html: post.html }} />;
}
💡 La ligne qui change tout — sans
revalidate, cette page est du SSG pur : figée jusqu’au prochain build. Avec, c’est de l’ISR : le premier visiteur après expiration reçoit encore l’ancienne version pendant que la nouvelle se génère derrière (stale-while-revalidate). Savoir expliquer cette ligne, c’est prouver qu’on a compris le spectre statique ↔ dynamique.
En entretien
« Explique la différence entre CSR, SSR et SSG. » — La question est : où et quand le HTML est produit. CSR : dans le navigateur, à l’exécution — coquille vide puis JS. SSR : sur le serveur, à chaque requête — HTML complet immédiat, hydraté ensuite. SSG : au build, une fois — HTML statique servi par CDN. Conclure par le critère de choix : fraîcheur des données et personnalisation contre coût et TTFB.
« Qu’est-ce que l’hydration et pourquoi est-elle nécessaire ? » — Le HTML issu du SSR est inerte : aucun event listener. L’hydration ré-exécute les composants côté client, rattache l’état et les événements au DOM existant. Nécessaire parce que l’interactivité vit dans le JS ; coûteuse parce qu’on paie le rendu deux fois — d’où l’écart FCP/TTI et les alternatives (islands, Server Components).
« Pourquoi une SPA CSR a-t-elle un mauvais SEO ? » — Le HTML initial est vide ; le contenu n’apparaît qu’après exécution du JS. Google finit par l’exécuter (avec délai et budget), mais les aperçus sociaux jamais. Si l’indexation compte, il faut le contenu dans le HTML : SSR, SSG ou pré-rendering.
« C’est quoi l’ISR et quel problème ça résout ? » — Le SSG ne passe pas à l’échelle du rebuild : 50 000 produits = 50 000 pages à régénérer pour corriger un prix. L’ISR régénère chaque page individuellement, en arrière-plan, après un délai (revalidate) ou sur demande (webhook du CMS). On garde le TTFB du statique avec une fraîcheur contrôlée.
« Quand choisirais-tu du CSR pur ? » — App derrière une authentification (dashboard, back-office, SaaS) : pas de SEO, utilisateurs récurrents (bundle en cache), interactivité riche. Le SSR y ajouterait de la complexité serveur pour un premier affichage que personne n’indexe.
Pièges & idées reçues
⚠️ « SSR = meilleure performance » — non : le SSR améliore le FCP et le SEO, mais dégrade le TTFB (calcul à chaque requête) et n’accélère pas l’interactivité (l’hydration reste à payer). Une page SSR lourde peut être visible vite et utilisable tard — la pire expérience : l’utilisateur clique dans le vide.
- « Le SEO exige du SSR » — le SSG donne un SEO tout aussi bon (le HTML est complet) pour bien moins cher. Le SSR ne s’impose que si le contenu change à chaque requête.
- Hydration mismatch : rendre
new Date().toLocaleString()ou du contenu dépendant dewindowau premier rendu → avertissement, re-rendu, flash. Client-only =useEffect(ouclient:onlyen Astro). - « Statique = pas de données dynamiques » — faux : une page SSG peut fetch côté client après chargement (commentaires, stock, likes). Coquille statique + îlots dynamiques est un pattern majeur.
- Tout mettre dans un îlot en Astro « au cas où » — on recrée une SPA en pièces détachées. Un îlot se justifie par une interaction réelle, sinon HTML statique.
- Oublier que ces stratégies se mélangent par route : répondre « SSR ou SSG ? » pour un site entier est déjà une erreur de cadrage — la bonne réponse commence par « quelle page ? ».
Pour aller plus loin
- Rendering on the Web (web.dev) — la cartographie de référence des stratégies de rendu
- Islands Architecture — le concept expliqué par la doc Astro (et le pattern original par Jason Miller)
- Next.js — Rendering : Server Components, streaming, statique vs dynamique
- Expérimenter :
curl -s https://votre-site | head -50— si le contenu est dans la réponse, c’est du SSR/SSG ; si c’est un<div id="root"></div>vide, c’est du CSR. Test à faire sur vos propres projets avant l’entretien.
The essentials
The whole web rendering question fits in one sentence: where and when is the HTML produced? Four possible answers, four strategies:
| CSR | SSR | SSG | ISR | |
|---|---|---|---|---|
| HTML produced | Browser (JS) | Server, per request | Build, once | Build + regeneration |
| TTFB | Fast (empty shell) | Slower (compute) | Excellent (static) | Excellent (static) |
| Initial content | Empty then fetch | Complete | Complete | Complete |
| SEO | Fragile | Good | Good | Good |
| Data freshness | Real time | Per request | Frozen at build | Periodic |
| Server cost | Near zero (CDN) | One render/request | Near zero (CDN) | Low |
| Typical example | Dashboard, SaaS | E-commerce, feed | Docs, blog, portfolio | Catalog, news |
- CSR (Client-Side Rendering): the server sends a near-empty page + a JS bundle; the browser downloads, executes, fetches the data, and builds the DOM. That’s the SPA model (React with Vite, for instance).
- SSR (Server-Side Rendering): the server executes the components on every request and returns complete HTML. The user sees content immediately… but it’s not interactive yet (see hydration).
- SSG (Static Site Generation): the HTML is generated at build time, once and for all, then served as-is from a CDN. Unbeatable in performance and cost — as long as the content doesn’t change on every request.
- ISR (Incremental Static Regeneration): SSG whose pages regenerate in the background after a delay expires (
revalidate). The best of static, with freshness on top.
How it works
The point candidates miss most: server-rendered HTML is not interactive. Event handlers (onClick…) only exist in the JS. Hence hydration: the browser downloads the bundle, re-executes the components, matches the result against the existing DOM, and attaches the events. Between first paint and the end of hydration, the page is visible but deaf — clicking does nothing.
SSR + hydration, timeline:
t0 ── request ──▶ server renders the HTML
t1 ◀── full HTML ──── FCP: the user SEES the page
t2 ◀── JS bundle ──── download + parsing
t3 ─── hydration ──── React re-executes and attaches
t4 ─── TTI ────────── the page RESPONDS to clicks
t1 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ t4
"uncanny valley": visible
but not interactive
In CSR, the timeline is inverted: nothing to see before t3, but as soon as it shows, it’s interactive. SSR optimizes First Contentful Paint, not Time To Interactive.
Two evolutions attack this hydration cost:
- Islands architecture (Astro): the page is static HTML by default, and only a few islands explicitly marked interactive (
client:load,client:visible) receive JS. The site you’re reading this card on works exactly like that: the content is static, the quiz is an island. Zero JS for the text, one small bundle for the interactive part. - Streaming SSR & Server Components (overview): rather than waiting for the whole page to be ready, the server streams HTML in chunks (
<Suspense>), and React Server Components never hydrate — their code never leaves the server, only the result travels. Less JS shipped, selective hydration.
🎤 In an interview — “why is your personal site SSG?” The best answer ties strategy to product: “the content changes when I decide (at deploy time), not on every visit. So I pay for rendering once at build, and serve pure HTML from a CDN: minimal TTFB, perfect SEO, free hosting, nothing to secure server-side. SSR would mean paying on every request to recompute an identical result.” You’ve just shown you pick architectures by their trade-offs, not by hype.
Key concepts to master
- Choose by product, not by fashion: identical content for everyone, rarely modified → SSG. Per-user or per-request content + SEO → SSR. App behind a login, no SEO stakes → CSR is plenty. Large catalog updated periodically → ISR.
- SEO and crawlers: Google executes JS, but with delay and a crawl budget; link previews (Slack, social networks) never execute it. Content that must be indexed or shared must be in the initial HTML.
- Hydration mismatch: if the client render doesn’t match the server HTML (
new Date(),Math.random(),window.innerWidth…), the framework warns and re-renders — visual flash and degraded perf. Rule: the first render must be deterministic; client-only values arrive in auseEffect. - The per-route mix: modern frameworks (Next.js, Nuxt, SvelteKit) pick the strategy page by page — landing in SSG, product page in ISR, cart in SSR or CSR. “Which rendering for this site?” is a per-route question, not a global one.
The canonical parameterized-SSG example, getStaticPaths:
// pages/blog/[slug].jsx — Next.js (Pages Router)
// At BUILD time: which pages should be generated?
export async function getStaticPaths() {
const posts = await cms.getAllPosts();
return {
paths: posts.map((p) => ({ params: { slug: p.slug } })),
fallback: "blocking", // unknown slug → rendered on the fly then cached
};
}
// At BUILD time, for each slug: the page's data
export async function getStaticProps({ params }) {
const post = await cms.getPost(params.slug);
if (!post) return { notFound: true };
return {
props: { post },
revalidate: 3600, // ISR: regenerated in the background at most hourly
};
}
// This component runs at build time (and during client-side hydration)
export default function BlogPost({ post }) {
return <article dangerouslySetInnerHTML={{ __html: post.html }} />;
}
💡 The line that changes everything — without
revalidate, this page is pure SSG: frozen until the next build. With it, it’s ISR: the first visitor after expiry still gets the old version while the new one generates behind the scenes (stale-while-revalidate). Being able to explain that line proves you’ve understood the static ↔ dynamic spectrum.
In an interview
“Explain the difference between CSR, SSR and SSG.” — The question is: where and when the HTML is produced. CSR: in the browser, at runtime — empty shell then JS. SSR: on the server, per request — immediate complete HTML, hydrated afterwards. SSG: at build time, once — static HTML served by CDN. Close with the decision criterion: data freshness and personalization versus cost and TTFB.
“What is hydration and why is it necessary?” — SSR HTML is inert: no event listeners. Hydration re-executes the components client-side and reattaches state and events to the existing DOM. Necessary because interactivity lives in JS; costly because you pay for rendering twice — hence the FCP/TTI gap and the alternatives (islands, Server Components).
“Why does a CSR SPA have poor SEO?” — The initial HTML is empty; content only appears after JS executes. Google eventually runs it (with delay and budget), but social link previews never do. If indexing matters, the content must be in the HTML: SSR, SSG or pre-rendering.
“What is ISR and which problem does it solve?” — SSG doesn’t scale with rebuilds: 50,000 products = 50,000 pages to regenerate to fix one price. ISR regenerates each page individually, in the background, after a delay (revalidate) or on demand (CMS webhook). You keep static TTFB with controlled freshness.
“When would you pick pure CSR?” — An app behind authentication (dashboard, back-office, SaaS): no SEO, recurring users (cached bundle), rich interactivity. SSR would add server complexity for a first paint nobody indexes.
Pitfalls & misconceptions
⚠️ “SSR = better performance” — no: SSR improves FCP and SEO, but worsens TTFB (compute per request) and doesn’t speed up interactivity (hydration still has to be paid). A heavy SSR page can be visible fast and usable late — the worst experience: the user clicks into the void.
- “SEO requires SSR” — SSG gives equally good SEO (the HTML is complete) for far cheaper. SSR is only mandatory when content changes on every request.
- Hydration mismatch: rendering
new Date().toLocaleString()orwindow-dependent content on first render → warning, re-render, flash. Client-only =useEffect(orclient:onlyin Astro). - “Static = no dynamic data” — wrong: an SSG page can fetch client-side after load (comments, stock, likes). Static shell + dynamic islands is a major pattern.
- Putting everything in an island in Astro “just in case” — you’re rebuilding a SPA in spare parts. An island is justified by an actual interaction, otherwise static HTML.
- Forgetting that these strategies mix per route: answering “SSR or SSG?” for a whole site is already a framing error — the right answer starts with “which page?”.
Going further
- Rendering on the Web (web.dev) — the reference map of rendering strategies
- Islands Architecture — the concept explained by the Astro docs (and the original pattern by Jason Miller)
- Next.js — Rendering: Server Components, streaming, static vs dynamic
- Experiment:
curl -s https://your-site | head -50— if the content is in the response, it’s SSR/SSG; if it’s an empty<div id="root"></div>, it’s CSR. Run this on your own projects before the interview.