SSR vs. CSR vs. SSG es una comparación de estrategias de renderizado según dónde y cuándo se genera el HTML: build, servidor o navegador. Ese único eje — dónde y cuándo — determina SEO, rendimiento, frescura de los datos y costo; todo lo demás es consecuencia. Y la aclaración de desarrollador de backend que las guías de frontend entierran: el renderizado es una preocupación del frontend; los datos son del backend. Las tres estrategias llaman a la misma API; solo difieren en el momento en que la llaman.
Puntos clave
| Pregunta | Respuesta |
|---|---|
| El eje | Dónde y cuándo nace el HTML — build · servidor · navegador |
| CSR | El navegador lo arma — mejor interactividad, peores primera carga y SEO |
| SSR | El servidor lo arma por solicitud — fresco, fuerte en SEO, TTFB mayor |
| SSG | Precompilado en el build, servido por CDN — el más rápido y barato, viejo hasta el próximo build |
| El reencuadre | La misma API, tres momentos de llamada — es por ruta, no por app |
Los mismos datos, tres momentos de llamada
// JavaScript — the SAME API call, consumed three ways.
// Rendering is a FRONTEND choice; the data is a BACKEND concern.
async function getPosts() {
const q = new Parse.Query('Post').equalTo('published', true).limit(20);
return q.find(); // one backend endpoint — the ONLY thing that changes is WHEN
}
// SSG — called at BUILD time; data baked into static HTML, served from a CDN.
// SSR — called PER REQUEST on the server; fresh HTML sent to the browser.
// CSR — called FROM THE BROWSER after load; the client builds the DOM.
// You don't change the backend to switch rendering — only when/where you fetch. // Flutter / Dart — Back4app Flutter SDK
// Whatever the rendering strategy, the data comes from one backend API.
Future<List<ParseObject>> getPosts() async {
final q = QueryBuilder<ParseObject>(ParseObject('Post'))
..whereEqualTo('published', true)
..setLimit(20);
return (await q.query()).results?.cast<ParseObject>() ?? [];
}
// SSG fetches at build, SSR fetches per request, CSR fetches in the client —
// the endpoint is identical; only the timing and location differ. // Swift — Back4app Swift SDK
// Whatever the rendering strategy, the data comes from one backend API.
func getPosts() async throws -> [Post] {
try await Post.query("published" == true).limit(20).find()
}
// SSG fetches at build, SSR fetches per request, CSR fetches in the client —
// the endpoint is identical; only the timing and location differ. // Kotlin — Back4app Android SDK
// Whatever the rendering strategy, the data comes from one backend API.
fun getPosts(): List<ParseObject> {
val q = ParseQuery.getQuery<ParseObject>("Post")
q.whereEqualTo("published", true)
q.limit = 20
return q.find()
}
// SSG fetches at build, SSR fetches per request, CSR fetches in the client —
// the endpoint is identical; only the timing and location differ. Un getPosts(), un endpoint de backend. El SSG lo llama en el build y hornea el resultado en HTML estático; el SSR lo llama en el servidor, por solicitud, y envía HTML fresco; el CSR lo llama desde el navegador, después de la carga. Nunca cambias el backend para cambiar el renderizado — solo el momento y el lugar del fetch. Ese es el hecho que convierte una comparación confusa de tres vías en una sola decisión.
SSR vs. CSR vs. SSG, lado a lado
| CSR | SSR | SSG | |
|---|---|---|---|
| HTML generado | En el navegador | En el servidor, por solicitud | En el build |
| TTFB | Rápido | Mayor (renderiza antes) | El más rápido, consistente |
| Primera pintura (FCP) | Lenta | Rápida | Rápida |
| Interactivo (TTI) | Lento | Tras la hidratación | Tras la hidratación |
| SEO | El más riesgoso | Fuerte | Fuerte |
| Frescura de los datos | En vivo | En vivo | Del último build |
| Costo | Servidor barato | Servidor por solicitud | El más barato (estático) |
| Mejor para | Dashboards, apps | Personalizado, fresco | Contenido, docs, marketing |
Las métricas, con honestidad
Los trade-offs que ninguna comparación enuncia con claridad. El SSG gana el time-to-first-byte de punta a punta y con consistencia — la CDN devuelve un archivo precompilado. El SSR sube el TTFB (el servidor debe renderizar antes de responder), pero aun así le gana al CSR en la primera pintura, y entrega datos frescos. El CSR tiene un TTFB rápido (el shell es minúsculo), pero primera pintura y time-to-interactive lentos, porque nada se ve hasta que el bundle corre. Y el punto que todos pasan por alto: SSR y SSG no arreglan el TTI. Ambos envían HTML que parece listo, y luego la hidratación — descargar, interpretar y ejecutar el JavaScript que anexa la interactividad — corre de todos modos. Es la brecha del “se ve listo pero no se puede clicar”, y por eso la cuenta de JS enviado es el verdadero impuesto de la interactividad — motivando islands, hidratación parcial y server components, que envían menos.
El espectro moderno: ISR, streaming, RSC
El trío es una simplificación didáctica; producción es un espectro. El ISR (incremental static regeneration) sirve páginas estáticas, pero regenera páginas individuales en un intervalo de revalidación o bajo demanda — velocidad de SSG con frescura periódica, al precio de alguna desactualización ocasional. El SSR con streaming envía el HTML en trozos a medida que se genera, así el shell pinta en decenas de milisegundos mientras el contenido lento llega detrás. Los server components corren solo en el servidor, envían cero JavaScript para las partes no interactivas y pueden leer datos directamente — la respuesta más nueva al costo de la hidratación. Ninguno cambia el contrato con el backend; son control más fino sobre cuándo se forma el HTML y cuánto JS lo sigue — el mismo eje sobre el que gira esta entrada entera.
Es por ruta, no por app
El upgrade mental que disuelve la mayoría de los debates de “¿cuál elijo?”: no eliges una estrategia para todo el sitio. Una sola app las mezcla de forma rutinaria — una home de marketing generada estáticamente, un catálogo de productos regenerado vía ISR, un dashboard personalizado renderizado en el servidor y widgets interactivos renderizados en el cliente — cada ruta eligiendo según sus propias necesidades. La pregunta nunca es “¿SSR, CSR o SSG para mi app?”, sino “¿cuál para esta página?”, y la respuesta sigue a los datos de la página: igual para todos y estable → estático; personalizado o fresco → servidor; detrás de un login y altamente interactivo → cliente.
¿Qué estrategia para cada página? Matriz de decisión
| Tipo de página | Renderizado |
|---|---|
| Marketing, landing, blog, docs | SSG |
| Catálogo de productos, noticias, feeds | ISR (estático + refresco periódico) |
| Personalizado, tras login, carrito, búsqueda | SSR (o streaming) |
| Dashboards, herramientas internas | CSR |
| Tiempo real, altamente interactivo | CSR + datos en vivo |
| Contenido crítico para SEO | CSR no — renderiza en el servidor o precompila |
Casos de uso comunes
- Sitios de contenido — SSG más una CDN para páginas instantáneas y amigables con los crawlers (el patrón JAMstack).
- E-commerce — catálogo en ISR, carrito y checkout en SSR, filtros interactivos en CSR — tres estrategias, una tienda.
- Dashboards SaaS — CSR detrás del login, donde el SEO no importa y la interactividad sí.
- Noticias y publishing — SSR o ISR para frescura con SEO.
- PWAs — un shell renderizado más interactividad en el cliente y caché offline.
Limitaciones y trade-offs
- El riesgo de SEO del CSR es real, pero exagerado. Los crawlers renderizan JavaScript con un presupuesto; CSR es tranquilo fuera del camino indexable y una apuesta dentro de él — matiz, no absolutismo.
- SSR cuesta cómputo de servidor. Renderizar cada solicitud tiene un precio en TTFB e infraestructura que un archivo estático servido por CDN no tiene.
- El rezago de frescura del SSG. Los datos del build quedan viejos hasta el próximo build; los sitios grandes o que cambian rápido necesitan ISR o builds largos.
- La hidratación es el impuesto escondido. El HTML renderizado en el servidor igual envía JS para volverse interactivo; primera pintura rápida, primer clic no tanto.
- Mezclar agrega carga cognitiva. El renderizado por ruta es poderoso y significa razonar sobre varios timings de fetch en una misma app — la flexibilidad tiene un costo de complejidad.
Renderizado en Back4app
Back4app es una plataforma open-source de Backend as a Service (BaaS) que combina base de datos gestionada, APIs REST y GraphQL generadas automáticamente, autenticación, almacenamiento de archivos y funciones serverless con Cloud Code. Es la constante debajo de la elección de renderizado: las APIs REST y GraphQL alimentan el SSG en el build, el SSR por solicitud en el servidor y el CSR desde el navegador — el endpoint idéntico de las pestañas de código, consumido en tres momentos distintos — de modo que cambiar la estrategia de una ruta nunca toca el backend. El reencuadre con el que abre este artículo se vuelve una comodidad de trabajo: como el renderizado es una decisión de frontend y los datos viven detrás de una API estable con su propia autenticación y sus permisos, un equipo puede precompilar el blog, renderizar el dashboard en el servidor y renderizar el shell de la app en el cliente contra el mismo backend de Back4app — eligiendo por página, sin cambiar nada por debajo.
Preguntas frecuentes
¿Qué es CSR (renderizado en el cliente)?
El servidor envía un HTML casi vacío más un bundle de JavaScript; el navegador descarga, interpreta y ejecuta el JS, trae los datos de una API y construye la página. El usuario ve una pantalla en blanco o un spinner hasta que el JavaScript corre — la mejor interactividad, la peor carga inicial y SEO.
¿Qué es SSR (renderizado en el servidor)?
El servidor genera el HTML completo en cada solicitud — ejecutando código y trayendo datos — y envía un documento listo para pintar, que luego se hidrata para ganar interactividad. SEO fuerte y primera pintura rápida con datos siempre frescos, al costo de cómputo en el servidor y un time-to-first-byte mayor.
¿Qué es SSG (generación de sitios estáticos)?
El HTML de cada página se precompila en el build en archivos estáticos y se sirve desde una CDN, sin trabajo de servidor por solicitud. La opción más rápida, barata y amigable con el SEO — pero los datos solo son tan frescos como el último build, y encaja mal en rutas desconocidas o muy dinámicas.
¿Cuál es la diferencia entre SSR, CSR y SSG?
Dónde y cuándo se genera el HTML: en el build (SSG), en el servidor por solicitud (SSR) o en el navegador en runtime (CSR). Todo lo demás — SEO, rendimiento, frescura de los datos, costo — se desprende de esa única elección.
¿Qué estrategia de renderizado es mejor para SEO?
SSG y SSR, porque los crawlers reciben HTML completo. CSR es la más riesgosa, ya que los bots deben ejecutar JavaScript para ver el contenido, lo que retrasa o puede costar la indexación. El matiz: los crawlers modernos sí renderizan JavaScript, pero con un presupuesto — CSR sirve para superficies no indexables y es una apuesta para contenido que debe rankear.
¿Qué es la hidratación (hydration)?
Anexar JavaScript — event listeners y estado — a un HTML ya renderizado en el servidor, para que una página de aspecto estático se vuelva interactiva. La trampa: el JS igual tiene que descargarse, interpretarse y ejecutarse, así que una página puede verse lista y seguir sin responder a los clics, retrasando el time-to-interactive aun cuando la primera pintura fue rápida.
¿Cuándo usar SSR y cuándo SSG?
SSG para contenido igual para todos y que cambia rara vez — docs, blogs, marketing. SSR para páginas personalizadas, detrás de autenticación o que cambian con la frecuencia suficiente para que los datos del build queden viejos. El consejo por defecto: prefiere SSG y recurre a SSR solo donde la frescura por solicitud sea obligatoria.
¿Se pueden mezclar estrategias en una misma app?
Sí — la práctica moderna es por ruta, incluso por componente: páginas de marketing estáticas, catálogo regenerado, dashboards renderizados en el servidor y widgets renderizados en el cliente conviven en una misma app. El renderizado es una decisión que tomas por página, no una vez para todo el sitio.