From n00b to ZeroCool / Profesionalización

SPA, SSR, SSG e ISR: la sopa de siglas que define si tu sitio vuela o se arrastra

Aprende SPA, SSR, SSG e ISR con ejemplos reales y un árbol de decisión para escoger según SEO, performance, costos y operación.

Lo que vale la pena leer aquí

Tu PM te escribe a las 6:48 pm: “Oye, el landing tiene que cargar rápido porque la campaña sale mañana y el SEO anda flojo”. Tú volteas a ver tu laptop ya guerita del teclado gastado, el build tarda como si estuviera minando crypto, y alguien del equipo suelta la frase comodín:

Tu PM te escribe a las 6:48 pm: “Oye, el landing tiene que cargar rápido porque la campaña sale mañana y el SEO anda flojo”. Tú volteas a ver tu laptop ya guerita del teclado gastado, el build tarda como si estuviera minando crypto, y alguien del equipo suelta la frase comodín:

“Pues… SSR, ¿no?”

Ahí arranca la sopa de siglas: SPA, SSR, SSG, ISR. Todas suenan a “sí, con eso se arregla”, hasta que te toca hacer deploy tarde, cachar un bug raro de caché, y explicarle a negocio por qué el contenido no se actualiza “en tiempo real” si lo “dejamos estático”.

La neta: no es religión, es logística de HTML. Qué generas, cuándo, y quién paga la cuenta cuando algo se rompe en production.

Qué te vas a llevar

  • Qué significa SPA vs SSR vs SSG vs ISR en términos de qué HTML llega y cuándo se genera.
  • Cómo se pelean con SEO, performance real, costo/infra y operación (cachés, invalidaciones, deploys).
  • Un árbol de decisión para elegir por página (no por framework).
  • Una estrategia híbrida típica que aguanta el jale (con Next.js como referencia mental, pero aplica a otros stacks).

La pregunta que sí importa

Estas siglas son estrategias para servir páginas. La pregunta real es:

¿Cuándo existe el HTML y quién lo genera: el server, el build o el navegador?

Y la que casi nadie hace hasta que truena production:

¿Quién se va a encargar de que el contenido sea “fresco”: tú, el caché, o una combinación peligrosa de ambos?

Dos escenas bien comunes:

  1. Campaña con presupuesto (Meta/Google): si el landing se tarda, el CPC se siente como mordida. “En mi wifi jala” no cuenta; en 4G con señal chueca en el metro, se cae el teatro.

  2. E-commerce con catálogo grande: “quiero todo indexado”, “todo rápido”, “y que el precio se actualice cuando lo cambie el ERP”. Ajá… y también sin subir el costo de infra.

Con eso en mente, vámonos por partes.

Guía principal: SPA/SSR/SSG/ISR sin llorar

1) SPA (Single Page Application): render en el cliente

Qué pasa: el server manda un HTML básico (casi vacío) + JavaScript. El navegador ejecuta JS, arma la UI, hace fetch de datos y renderiza.

Cómo se siente:

  • Primera carga pesada si tu bundle está gordo.
  • Navegación interna rápida.
  • SEO “depende”: Google a veces ejecuta JS, pero no siempre como tú quieres (y otros bots ni de broma).

Cuándo sí conviene:

  • Apps internas (dashboards, CRMs, tickets).
  • Producto donde el usuario sí o sí inicia sesión.
  • Flujos muy interactivos donde el contenido no necesita indexarse.

Tradeoff real: si tu objetivo es adquisición orgánica, una SPA sin prerender es como abrir un local con la cortina abajo y esperar que entre gente.

Ejemplo rápido:

  • Panel de soporte: SPA, sin miedo.
  • Blog/landing principal: mala idea si te vas full client sin prerender.

2) SSR (Server-Side Rendering): HTML en cada request

Qué pasa: cada request genera HTML en el server (o en edge). Luego “hidratas” en el cliente para que haya interactividad.

Cómo se siente:

  • Mejor arranque percibido si está bien cacheado y no haces cosas raras.
  • SEO suele mejorar porque el HTML ya trae contenido.
  • Costo por request: el server trabaja cada vez.

Cuándo sí conviene:

  • Contenido dinámico por usuario/permisos.
  • Páginas donde la frescura es crítica (precio/stock, feeds personalizados).
  • Cuando no puedes pre-generar por combinaciones infinitas.

Tradeoff real:

  • SSR sin caché = “bonito en dev, caro y lento en production”.
  • SSR pegándole a una API lenta = tu server se vuelve el cuello de botella.

3) SSG (Static Site Generation): HTML en build

Qué pasa: generas HTML en build time. Sirves archivos estáticos por CDN.

Cómo se siente:

  • Rápido, como caché calentito.
  • Barato de servir.
  • SEO feliz.

Cuándo sí conviene:

  • Marketing, docs, blogs, páginas casi inmutables.
  • Catálogos que cambian poco o donde toleras un delay.

Tradeoff real: si tienes miles de páginas y cambian seguido, los builds se vuelven eternos. Y sale el clásico: “ya lo cambié en el CMS pero el sitio no”.

4) ISR (Incremental Static Regeneration): estático con refresh controlado

Qué pasa: sirves estático, pero ciertas páginas se regeneran en background según una política (por tiempo o bajo demanda con revalidación).

Cómo se siente:

  • Performance de estático casi siempre.
  • Actualizaciones sin rebuild completo.
  • Complejidad extra: cachés, invalidación, contenido stale y comportamientos raros en edge.

Cuándo sí conviene:

  • Catálogos y blogs con contenido frecuente.
  • Landings que cambian cada semana.
  • Sitios grandes donde SSG total ya no escala.

Tradeoff real: ISR te ahorra talacha de builds, pero te cobra en operación: saber qué se revalida, cuándo, y por qué alguien vio “lo de hace 10 minutos”.


Árbol de decisión (rápido pero usable)

Hazte estas preguntas por tipo de página:

  1. ¿Necesita SEO fuerte?
  • No → SPA (o SSR si tu app lo exige)
  • Sí → SSR/SSG/ISR
  1. ¿Cambia seguido el contenido?
  • No / raro → SSG
  • Sí, pero tolero retraso (minutos) → ISR
  • Sí, y debe estar fresco siempre → SSR
  1. ¿Es personalizado por usuario?
  • Sí → SSR (o SPA + API, pero SEO se complica)
  • No → SSG/ISR
  1. ¿Tu build ya se está muriendo?
  • Sí → ISR o SSR selectivo; SSG total deja de escalar.

La decisión madura casi siempre es híbrida: no todo el sitio tiene que renderizar igual.

Estrategia híbrida que sí sobrevive a producción

Piensa en Next.js para aterrizar ideas (pero esto se traduce igual a Nuxt, SvelteKit, Astro, etc.).

Paso 1: clasifica rutas como si fueras SRE 10 minutos

Arma una tablita (tal cual en tu pull request) con algo así:

  • / home (SEO, cambia poco)
  • /blog/[slug] (SEO, cambia seguido)
  • /producto/[id] (SEO, cambia por precio/stock)
  • /checkout (no SEO, personal)
  • /dashboard (no SEO, personal)

Si no lo puedes explicar en una tabla, probablemente tu setup ya está demasiado enredado.

Paso 2: asigna estrategia por ruta (sin casarte)

Un combo típico que funciona:

  • Home + marketing → SSG
  • Blog posts → ISR (revalidación cada X)
  • Producto → ISR si toleras minutos de desfase; SSR si no
  • Checkout/Dashboard → SPA (o SSR solo por auth, depende)

Ojo: esto no es “lo correcto universal”, es “lo que te evita un rollback a medianoche”.

Paso 3: mide lo que duele (no lo que se ve bonito en tu máquina)

Métricas que sí cambian decisiones:

  • TTFB (SSR sin caché se delata aquí)
  • LCP (HTML temprano ayuda, pero imágenes y fuentes también)
  • JS bundle size (hidratar de más te mata igual con SSR/SSG)
  • Cache hit ratio (cuando metes CDN/edge)

Regla de barrio: prueba en 4G simulado + CPU throttling. Tu laptop gamer no representa al usuario con Android gama media.

Paso 4: “hidrata solo lo que respira”

SSR/SSG/ISR te dan HTML, pero si hidratas toda la página como si fuera app, pagas en JS.

  • Componentes interactivos: sí, hidrata.
  • Texto, layout, contenido: déjalo quieto.

Traducción práctica:

  • Separar Server/Client components (si aplica en tu stack)
  • Evitar estados globales donde no hacen falta
  • Lazy-load de widgets pesados (chat, mapa, carruseles)

Paso 5: define tu política de frescura (y déjala escrita)

Esto evita el “¿por qué no se actualiza?” cuando ya te ibas a dormir.

  • Blog: revalida cada 10–30 min
  • Producto: revalida cada 1–5 min, o on-demand cuando cambie precio
  • Home: revalida cada hora o por deploy

En Next (ejemplo conceptual):

// ISR por tiempo (conceptual)
export const revalidate = 300; // 5 min

On-demand revalidation (conceptual):

// endpoint protegido que revalida cuando el CMS publica
// (conceptual; varía por versión/framework)
export async function POST(req) {
  // validar firma/token del CMS
  // revalidatePath('/blog/mi-post')
  return Response.json({ ok: true });
}

El snippet es lo de menos. Lo clave es tener un trigger (webhook del CMS/ERP) y un contrato de frescura que negocio entienda.

SPA, SSR, SSG e ISR: la sopa de siglas que define si tu sitio vuela o se arrastra - visual explicativa 1
Visual de apoyo: Qué te vas a llevar

Screenshots sugeridos

  1. DevTools Performance/Lighthouse mostrando LCP/TTFB antes y después (misma página en SSR vs SSG).
  2. Diagrama simple de flujo: Request → CDN cache → server render vs static file.
  3. Captura de logs/monitoring con picos de latency cuando SSR pega a API lenta.
  4. Pantalla de tu CMS/webhook o endpoint de revalidación (con datos sensibles ocultos).

Errores comunes (y cómo salir vivo)

Error 1: “Hagamos SSR para todo y ya”

Síntoma: al principio “se siente rápido”, llega tráfico y el server se ahoga.

Salida: SSR selectivo + cache/CDN + no pegarle a la DB en cada request. Si no es personalizado, probablemente no necesita SSR.

Error 2: SSG para catálogo enorme y builds interminables

Síntoma: el deploy tarda 25–40 min, el CI se llena, publicar es peregrinación.

Salida: ISR para catálogo y SSG solo para lo realmente estable.

Error 3: “Tenemos ISR” pero sin estrategia de invalidación

Síntoma: cambian precio en el admin y el sitio tarda; te cae el “¿ya quedó?”

Salida: define revalidate por tipo de página + on-demand revalidation cuando el origen cambie.

Error 4: SEO raro porque la página depende de JS

Síntoma: tú ves contenido, pero Search Console muestra titles/metas inconsistentes o snippets vacíos.

Salida: asegura HTML con contenido relevante (SSR/SSG/ISR) y metas por ruta. No dependas de JS para title/description.

Error 5: hidratas todo y matas performance

Síntoma: TTFB bien, pero LCP/INP mal. Mucho JS, mucha re-render.

Salida: baja JS, divide bundles, hidrata solo lo necesario, lazy-load lo no crítico.

SPA, SSR, SSG e ISR: la sopa de siglas que define si tu sitio vuela o se arrastra - visual explicativa 2
Visual de apoyo: La pregunta que sí importa

Checklist final (para decidir sin volarte la noche)

  • ¿Esta página necesita SEO? (sí/no)
  • ¿El contenido es público o personalizado?
  • ¿Con qué frecuencia cambia y cuánto retraso tolera negocio?
  • ¿Qué tan caro es generar la página (API/DB/terceros)?
  • ¿Tengo cache/CDN y sé si pega hit o miss?
  • ¿Mi build escala o ya está tronando?
  • ¿Qué tanto JS estoy mandando? (hidratar solo lo necesario)
  • ¿Tengo monitoreo de TTFB y LCP en producción?

FAQ

1) ¿SSR siempre es mejor para SEO?

Suele ayudar porque entregas HTML con contenido desde el server, pero SEO también depende de metas, canonical, estructura, performance e indexabilidad. SSR lento o con contenido incompleto también pierde.

2) ¿SSG es “gratis” en performance?

Servir estático por CDN es rapidísimo, pero lo puedes arruinar con imágenes pesadas, JS excesivo o fuentes mal cargadas. SSG te da base, no inmunidad.

3) ¿ISR significa que ya no necesito rebuild?

Vas a necesitar deploy para cambios de layout, dependencias o rutas nuevas. ISR te evita rebuilds completos por cambios de contenido. Es “menos rebuild”, no “cero deploys”.

4) ¿Puedo mezclar estrategias en el mismo proyecto?

Sí, y normalmente es lo correcto: home en SSG, blog en ISR, producto en ISR/SSR, dashboard en SPA. Elegir por ruta te da performance y control.

5) ¿Qué elijo si tengo deadline y no sé?

Si es landing/blog y te urge SEO + velocidad: SSG. Si cambia seguido: ISR con un revalidate razonable. Evita SSR global si no tienes caché y observabilidad listos.

Siguiente episodio: teaser

La sopa de siglas no termina: toca hablar de hidratación, islands y Server Components.

Porque sí: puedes tener SSR/SSG y aun así mandar demasiado JS… y eso también se paga.