06 ago 2025·8 min de lectura

Caché CDN para Next.js: encabezados de caché sin filtraciones de usuarios

El caché CDN para Next.js acelera páginas y recursos, pero encabezados mal configurados pueden guardar datos de usuarios. Aprende qué cachear, ejemplos de encabezados y trampas.

Caché CDN para Next.js: encabezados de caché sin filtraciones de usuarios

Por qué el caché CDN puede romper una app Next.js

Los CDN hacen que los sitios se sientan rápidos guardando copias de lo que envía tu servidor y sirviéndolas desde un lugar cercano al visitante. Bien hecho, reduce el tiempo de carga y el coste del servidor. Hecho sin cuidado, puede romper inicios de sesión, mostrar datos equivocados o parecer que "se arregla al azar" más tarde.

Un CDN puede cachear dos tipos de cosas:

  • Archivos (imágenes, JS, CSS)
  • Respuestas HTTP completas (HTML de una página, JSON de una ruta API)

La parte complicada es que una app Next.js a menudo sirve tanto páginas públicas como páginas específicas de usuario desde el mismo dominio. Si tu CDN las trata igual, puedes terminar cacheando algo que nunca debería compartirse.

Dos problemas generan la mayoría de los dolores de cabeza:

  • Contenido obsoleto: actualizas una página, pero la gente sigue viendo la versión antigua porque estaba en caché.
  • Respuestas personales cacheadas: el CDN guarda una respuesta pensada para una persona y luego se la sirve a otra.

Un fallo común se ve así: tienes una página de marketing y un dashboard en /app. Un usuario inicia sesión, visita /app y el servidor devuelve HTML que incluye su nombre y actividad reciente. Si esa respuesta HTML queda en caché, el siguiente visitante que pida /app podría ver la interfaz del primer usuario o quedarse en un bucle de autenticación roto.

Así que el caché CDN para Next.js no es tanto "activar caché" como establecer reglas claras. Decide qué es seguro cachear (normalmente activos estáticos y páginas verdaderamente públicas), qué nunca debe cachearse (HTML personalizado, flujos de auth y la mayoría de APIs específicas de usuario) y cuánto tiempo debe vivir el contenido en caché.

Mapea tu app en partes cacheables y no cacheables

Antes de tocar encabezados, mapea lo que tu app realmente sirve. El caché CDN funciona mejor cuando tratas cada tipo de respuesta de forma distinta. Una regla única para todo es cómo los datos de usuario acaban cacheados por error.

Empieza listando los principales tipos de respuesta que devuelves:

  • Archivos estáticos (JS, CSS, fuentes)
  • Imágenes (incluidas variantes optimizadas)
  • Páginas HTML (marketing, docs, dashboards)
  • Respuestas de API (JSON, webhooks, callbacks de auth)

Luego agrupa tus rutas según lo públicas que sean:

Grupo de rutasEjemplos¿Se puede cachear en CDN?¿Cambia a menudo?
Público/, /pricing, /blog/*Normalmente síA veces
Semi-público/account, /checkoutNormalmente noA menudo
Privado/dashboard, /adminNoA menudo

Ahora marca las áreas de "alto cambio". Precios, inventario y cualquier cosa que muestre estado en vivo (pedidos, uso, mensajes) pueden quedarse obsoletos rápidamente. Los dashboards son el ejemplo obvio, pero las páginas de checkout, pasos de onboarding e incluso bloques de "Bienvenido de nuevo" pueden ser personalizados.

Diferentes tipos de contenido necesitan distintas reglas porque los riesgos difieren. Cachear agresivamente un bundle JS suele ser seguro. Cachear HTML que depende de cookies puede filtrar la página de un usuario a otro.

Un ejemplo del mundo real: un sitio tiene una página de marketing pública, pero el encabezado muestra el nombre del usuario cuando está logueado. Ese detalle convierte una página cacheable en algo arriesgado a menos que separes la experiencia (plantilla pública más datos privados cargados aparte) o desactives el caché cuando hay cookies.

Cachea activos estáticos de forma segura (JS, CSS, fuentes, imágenes)

Los activos estáticos son la victoria más fácil porque normalmente no cambian por usuario. Piensa en archivos que el navegador descarga y reutiliza en muchas páginas.

Activos típicos:

  • Archivos de build de Next.js bajo /_next/static/ (chunks JS, CSS)
  • Fuentes e íconos (woff2, ttf, svg)
  • Imágenes y favicons
  • Todo lo que esté en tu carpeta public/

Para archivos versionados (los que llevan un hash en el nombre), un caché de larga duración es la opción correcta por defecto. El hash cambia cuando el contenido cambia, así que el archivo es efectivamente inmutable.

Un encabezado común para estos es:

Cache-Control: public, max-age=31536000, immutable

Antes de poner un TTL de un año, asegúrate de que "immutable" sea realmente cierto en tu flujo. Si sirves logo.png desde public/ y luego reemplazas el archivo manteniendo el mismo nombre, un TTL largo puede dejar el logo antiguo en cachés por mucho tiempo. Para nombres no versionados, mantén TTLs más cortos o añade un paso de build que marchee los nombres.

Las imágenes a menudo necesitan su propia estrategia. Si generas varios tamaños o formatos (como WebP y AVIF), el caché es seguro solo cuando la URL final identifica de forma única la salida. Si un endpoint de imagen optimizada varía por ancho, calidad o formato, esas entradas deben formar parte de la clave de caché. De lo contrario, los usuarios pueden recibir la variante equivocada.

Una comprobación rápida: elige un chunk JS y una fuente, ábrelos y confirma que nunca cambian a menos que despliegues una nueva build.

Cachea páginas y HTML: qué es seguro y qué es arriesgado

El mayor beneficio (y el mayor riesgo) es cachear HTML completo. El HTML es lo que ve el usuario, así que si cacheas lo equivocado puedes mostrar la información equivocada a la persona equivocada.

HTML seguro para cachear suele ser contenido igual para todos: páginas de marketing, precios, docs, páginas públicas y la mayoría de entradas de blog. Una prueba simple: abre la página en una ventana de incógnito. Si se ve igual conectado y desconectado, es un buen candidato.

HTML arriesgado para cachear es cualquier cosa que cambie por usuario, por sesión o según datos privados: dashboards, ajustes de cuenta, checkout, historial de pedidos, páginas que muestran un nombre, email, elementos guardados, estado de facturación o "tu última conexión...". Cachear esto en el CDN es cómo ocurren las filtraciones de datos.

Una regla práctica:

  • Cachea páginas públicas con tiempos controlados.
  • No cachees páginas de usuario a menos que estés 100% seguro de que la respuesta es idéntica para todos.
  • En caso de duda, trata el HTML como privado y desactiva el caché.

ISR (Incremental Static Regeneration) está en el medio. Permite a Next.js servir una página en caché rápidamente y actualizarla en segundo plano según un temporizador. Es ideal para páginas que cambian ocasionalmente, como posts de blog. No es buena opción para páginas personales, porque la frescura no soluciona el problema de "usuario equivocado".

Otro detalle: cachear HTML no es lo mismo que cachear llamadas de datos. Una página puede ser segura para cachear mientras que una API que llama no lo sea. O puedes mantener el HTML privado y cachear datos verdaderamente públicos (como un listado de productos) con un TTL corto. Confundir esto provoca que "funcionó en staging" se convierta en contenido obsoleto o exposición accidental.

Encabezados de caché que necesitas conocer (sin jerga)

La mayoría de problemas de caché vienen de una cosa: el CDN y el navegador adivinan cuánto tiempo es seguro reutilizar algo. Los encabezados de caché son cómo se lo dices, claramente.

Cache-Control: el principal

Cache-Control es un conjunto de instrucciones. Las partes más comunes son:

  • max-age=...: cuánto tiempo puede guardarlo el navegador (segundos)
  • s-maxage=...: cuánto tiempo pueden guardarlo caches compartidos (un CDN). Si está presente, los CDNs suelen seguir esto en lugar de max-age.
  • public: ok para almacenar en un caché compartido
  • private: solo el navegador del usuario puede almacenarlo (un CDN no debería)
  • no-store: no lo almacenes en ningún lado (uso para respuestas personales o sensibles)

Una regla simple: si la respuesta puede alguna vez diferir por usuario, evita public. Para dashboards y páginas de cuenta, por defecto usa no-store a menos que tengas una razón muy específica para no hacerlo.

stale-while-revalidate: mostrar viejo, refrescar en segundo plano

stale-while-revalidate=... permite a un caché servir una versión algo antigua por un tiempo corto mientras obtiene una versión nueva. Funciona bien para contenido que puede estar un poco desactualizado (como una página de marketing). Es arriesgado para cualquier cosa que deba ser correcta en el momento (facturación o permisos).

ETag y Last-Modified: cómo los caches comprueban si algo cambió

Con ETag o Last-Modified, un caché puede preguntar: "¿Esto cambió?" Si no, el servidor responde con una pequeña respuesta "not modified" en vez de reenviar todo el cuerpo. Esto importa cuando las respuestas son grandes, el contenido se actualiza a menudo o quieres actualizaciones rápidas sin apagar el caché.

Vary: la etiqueta de "depende de"

Vary indica a los caches qué encabezados de la petición pueden cambiar la respuesta. Esto importa cuando hay cookies o auth involucrados.

Si el HTML cambia según el estado de login y no manejas Vary junto con reglas de caché, un CDN puede servir la versión de un usuario a otro. Vary comunes incluyen Cookie, Authorization y Accept-Encoding.

Paso a paso: establece reglas de caché para una app Next.js típica

Haz las reglas de caché predecibles
Diagnosticamos rutas enmarañadas e incoherencias en Cache-Control para que tus reglas CDN sean previsibles.

Una forma práctica es empezar por lo más seguro y luego avanzar hacia contenido que puede cambiar.

1) Empieza por los objetivos más seguros

Comienza con archivos idénticos para todos: bundles JavaScript, CSS, fuentes y imágenes versionadas. Son bajo riesgo y suelen dar la mayor mejora de velocidad.

2) Ajusta tiempos según lo que pueda cambiar

Usa cachés muy largos para activos inmutables (archivos que cambian nombre cuando el contenido cambia). Para páginas y HTML, usa cachés más cortos porque el contenido puede actualizarse sin cambiar el nombre del archivo.

Una lista de comprobación práctica:

  • Empieza con /_next/static/*, tus activos claramente versionados y otros archivos con nombres hasheados.
  • Para activos inmutables, envía un Cache-Control largo más immutable.
  • Para páginas públicas no personalizadas (marketing, docs), usa un caché compartido más corto (minutos a horas) y considera stale-while-revalidate.
  • Para cualquier cosa específica de usuario (dashboards, páginas de cuenta, rutas API que dependen de cookies), fuerza Cache-Control: private o no-store.
  • Decide cómo invalidarás la caché: confía en despliegues que cambien nombres de archivos y ten un plan claro de purgado para HTML cuando publiques actualizaciones urgentes.

3) Prueba antes de confiar

No te quedes en "carga rápido". Haz un refresco duro y compara comportamiento desconectado vs conectado.

Una comprobación rápida: abre la misma página en una ventana de incógnito y en una sesión logueada. Si HTML, encabezados o datos visibles coinciden cuando no deberían, trátalo como una filtración y deja de cachear esa ruta.

Claves y reglas de caché del CDN que deciden qué se sirve

Un CDN no "cachea una página" en abstracto. Cachea una respuesta bajo una clave de caché. Esa clave suele construirse a partir de la ruta de la petición y, a veces, de la query string, encabezados y cookies.

Si la clave es demasiado amplia, los usuarios verán contenido equivocado. Si es demasiado específica, obtendrás una baja tasa de aciertos y páginas más lentas.

Qué suele pertenecer a la clave de caché

Empieza simple: para páginas públicas, la ruta suele ser suficiente. Añade otras partes solo cuando realmente cambien lo que el usuario debe ver.

  • Ruta: /pricing vs /blog/slug deben ser separadas.
  • Params de consulta: incluye solo los que cambian contenido (por ejemplo, ?page=2). Ignora params de tracking como utm_*.
  • Encabezados: incluye solo variantes reales (por ejemplo, idioma).
  • Cookies: evita usar cookies para contenido público. Multiplican las variantes de caché.

El caso peligroso es cuando un CDN cachea una respuesta personalizada porque había una cookie presente. Incluso si la cookie no es parte de la clave, cachear una respuesta personalizada aún puede filtrar datos.

Variantes: locale y dispositivo

Si tu HTML cambia por locale, usa una señal clara y varía en ella (a menudo Accept-Language o un encabezado dedicado que controles).

Ten cuidado con la variación por dispositivo. Variar por User-Agent crea demasiadas versiones y es fácil equivocarse. Prefiere diseño responsivo o un encabezado pequeño y explícito si realmente necesitas HTML separado.

Finalmente, establece reglas de bypass para lo que nunca debe cachearse: /admin, rutas /api que devuelven datos personales, dashboards autenticados y cualquier ruta que compruebe una cookie de sesión.

Cómo evitar cachear respuestas personalizadas

Rescata Next.js generado por IA
¿Tienes un codebase generado por IA? Ayudamos a dejarlo listo para producción con límites de caché claros.

Un CDN es genial hasta que guarda por accidente una respuesta destinada a una persona y se la sirve a otra. Ese es el mayor riesgo: HTML o JSON cacheado puede convertirse en una fuga de datos si incluye nombre, email, estado de facturación o cualquier cosa ligada a una sesión.

La personalización suele colarse por cookies y encabezados de auth. Si una petición incluye Cookie u Authorization, asume que puede producir salida específica de usuario a menos que estés completamente seguro de que no.

Usa encabezados de caché claros para todo lo que esté detrás de login. Para dashboards, ajustes, páginas de facturación y rutas API específicas de usuario, prefiere Cache-Control: no-store (o al menos private, no-store). Eso dice a navegadores y CDNs que no guarden una copia.

Señales prácticas que deberían llevarte a no cachear:

  • La petición incluye Cookie, Authorization o un encabezado de token de sesión.
  • La respuesta depende de quién es el usuario (incluso si la URL es la misma).
  • El HTML incluye datos de cuenta, actividad reciente o estado de facturación.
  • Una API devuelve registros de usuario, tokens o cualquier cosa sensible.
  • No puedes explicar tu clave de caché en una frase.

Las páginas mixtas son complicadas. Un patrón común es una plantilla pública que también muestra "Hola Sam" o un contador de notificaciones cuando hay sesión. Si el HTML está personalizado, no lo cachees públicamente. Un patrón más seguro: cachea la plantilla pública y luego solicita fragmentos personalizados desde el cliente (o desde un endpoint no cacheable).

Si puedes, separa endpoints públicos y privados para que tus reglas sean simples. Mantén rutas cacheables claramente públicas y rutas autenticadas claramente no cacheables.

Errores comunes que causan contenido obsoleto o fugas de datos

La mayoría de fallos de caché ocurren cuando algo "pareció rápido" en una prueba rápida, pero se comporta distinto cuando usuarios reales inician sesión. El peligro no es solo páginas obsoletas. También es servir contenido de una persona a otra.

Errores recurrentes:

  • Cachear HTML de rutas con login porque en pruebas anónimas parecía seguro.
  • Marcar respuestas como public aunque cambien según cookies, un encabezado auth o geolocalización.
  • Dar un max-age largo a activos no versionados (como /app.css), luego lanzar una actualización y los usuarios mantienen el archivo antiguo.
  • Olvidar que redirects, páginas de error y 404s también pueden cachearse, lo que puede fijar una caída temporal o una ruta equivocada.
  • Confiar en el comportamiento por defecto del hosting o del framework sin comprobar lo que el CDN realmente está almacenando.

Una forma rápida de detectar riesgo: pregúntate, "¿Podría esta respuesta ser diferente para dos usuarios?" Si la respuesta es sí, no debe cachearse públicamente. Incluso una pequeña diferencia como un saludo significa que el HTML está personalizado.

También vigila el caché invisible: un 302 hacia /login cacheado, un 404 cacheado para una página recién lanzada o un 500 cacheado durante un despliegue.

Comprobaciones rápidas antes de llevar el caché a producción

Antes de desplegar el caché, haz una pasada rápida con peticiones reales, no solo lo que esperas que haga tu código. Pequeños errores en encabezados pueden convertirse en páginas obsoletas o, peor, la persona equivocada viendo datos de otro.

Empieza con lo básico:

  • Páginas públicas iguales para todos deben enviar Cache-Control: public y un s-maxage sensato para que el CDN las cachee.
  • Todo lo que esté detrás de login debe ser Cache-Control: private o no-store.

Si dudas, por defecto usa no-store y afloja después.

Comprobaciones previas al despliegue que atrapan la mayoría de problemas:

  • Abre una página pública y confirma que realmente es cacheable (Cache-Control: public con s-maxage).
  • Abre una página autenticada y confirma que no es cacheable por cachés compartidos (private o no-store, nunca public).
  • Revisa activos estáticos: el caché largo solo es seguro cuando los nombres de archivo están versionados (hash en el nombre). Si no, mantén el caché corto.
  • Llama a APIs que devuelven datos de usuario y confirma que no son cacheadas por el CDN.
  • Prueba con dos cuentas: inicia sesión como Cuenta A en un navegador, Cuenta B en otro, y carga las mismas URLs. Nada personal debe cruzarse.

También vigila parámetros de consulta. Si tu CDN cachea por URL completa, ?ref=, ?utm_ y filtros aleatorios pueden crear variantes de caché infinitas. Decide qué params deben ignorarse y cuáles forman parte de la clave.

Un ejemplo realista: sitio de marketing + dashboard en el mismo dominio

Reparaciones con respuesta rápida
La mayoría de las correcciones se implementan en 48 a 72 horas después de identificar los problemas contigo.

Una startup lanza una app Next.js que mezcla un sitio de marketing público y un dashboard logueado bajo el mismo dominio. El tráfico sube después de lanzamientos, así que añaden caché CDN para mantener las páginas rápidas.

La separan en dos grupos.

Cachea lo que es seguro e idéntico para todos:

  • JS y CSS versionados (caché largo, porque los nombres cambian al desplegar)
  • Imágenes, fuentes e íconos (caché largo si los nombres están versionados; más corto si se sobrescriben)
  • Páginas de marketing como /, /pricing, /blog (TTL corto en CDN para que las ediciones aparezcan rápido)

Para el HTML de marketing ponen un TTL compartido corto y una ventana pequeña de stale-while-revalidate. El CDN puede servir una página algo antigua por un momento mientras la refresca.

Nunca cachees lo que varía por usuario:

  • /dashboard y todo lo que esté bajo esa ruta
  • Páginas de ajustes y facturación
  • /api/user (y cualquier cosa que devuelva datos de cuenta)
  • Páginas de autenticación y callbacks

Para verificar que no crearon una fuga, prueban como un cliente paranoico: dos cuentas, dos navegadores, refresco duro y una comprobación rápida de encabezados. Las páginas personalizadas jamás deben mostrar directivas public.

Cuando algo falla (un usuario ve el nombre equivocado o estado de suscripción obsoleto), primero revierten la regla del CDN. Luego endurecen los encabezados en las rutas riesgosas (empieza por /dashboard y /api) antes de volver a habilitar cualquier caché.

Próximos pasos: desplegar con seguridad y pedir ayuda si está complicado

Empieza pequeño y haz que las mejoras sean aburridas. Cachea activos estáticos inmutables (JS y CSS hasheados, fuentes, imágenes versionadas) con TTLs largos. Cuando eso esté estable, añade caché para páginas verdaderamente públicas. Trata cualquier cosa que pueda variar por usuario, cookie o auth como no cacheable a menos que la hayas diseñado explícitamente para edge caching.

Escribe tus reglas de caché en inglés claro. Muchos errores de caché aparecen meses después cuando alguien añade un nuevo encabezado, introduce un redirect o cambia auth. Un breve "contrato de caché" facilita las revisiones: qué es cacheable, qué nunca cachear y qué señales (cookies, encabezados, params) cambian la respuesta.

Si heredaste un codebase generado por IA, revisa doblemente encabezados y flujos de auth. Estos proyectos a menudo vienen con patrones de routing mixtos, Cache-Control inconsistentes y sesiones que funcionan localmente pero se rompen detrás de un CDN.

Si estás viendo autenticación rota, comportamiento de caché arriesgado o simplemente no puedes explicar con confianza lo que tu CDN está almacenando, FixMyMess (fixmymess.ai) hace diagnóstico de codebase y reparaciones para apps generadas por IA, incluyendo desenredar encabezados de caché y fronteras de auth. También ofrecen una auditoría de código gratuita para identificar problemas antes de cambiar nada en producción.