Cache-Control — qué es, directivas y gestión del almacenamiento en caché

Autor: IT Sectr Publicado: 2026-03-09 Tiempo de lectura: 9 min

Cache-Control es un encabezado HTTP que define las reglas de almacenamiento en caché de los recursos en el cliente, los servidores proxy y las CDN mediante un conjunto de directivas. A diferencia del obsoleto encabezado Expires, Cache-Control admite docenas de combinaciones: max-age establece el tiempo de vida en segundos, private y public controlan la disponibilidad de la caché, no-cache y no-store — verificación forzada. Según Google Web Dev (2025), una configuración correcta de Cache-Control puede reducir el tiempo de carga de las páginas en un 50-80% para las visitas repetidas. Esto hace que el encabezado sea críticamente importante para el rendimiento de aplicaciones web y móviles.

Puntos clave

  • Cache-Control — un encabezado HTTP con directivas que controlan el almacenamiento en caché en el cliente, proxy y CDN
  • max-age — una directiva clave que establece el tiempo de vida del recurso en segundos sin necesidad de revalidación
  • private vs public — private permite el caché solo en el cliente, public también en proxies y CDN
  • no-cache vs no-store — no-cache requiere validación antes de usar, no-store prohíbe el caché por completo
  • s-maxage — anula max-age para cachés compartidos sin afectar a los navegadores

¿Qué es Cache-Control?

Cache-Control es un encabezado HTTP, estandarizado en HTTP/1.1 (RFC 7234), que permite al servidor especificar cómo y durante cuánto tiempo los clientes, proxies y CDN pueden almacenar en caché la respuesta. A diferencia de Expires (HTTP/1.0), Cache-Control utiliza directivas — comandos de texto combinados con comas: Cache-Control: public, max-age=3600, must-revalidate. El encabezado proporciona un control detallado sobre cada eslabón de la cadena de caché.

El almacenamiento en caché es uno de los mecanismos fundamentales del rendimiento de aplicaciones web y móviles. Sin él, cada solicitud del usuario iría directamente al servidor, provocando una carga excesiva y latencia. Cache-Control define tres niveles de caché: navegador/aplicación (caché privada), servidores proxy (caché compartida) y CDN (caché distribuida). Cada nivel interpreta las directivas de manera diferente.

La configuración incorrecta de Cache-Control es una de las causas más comunes de problemas de rendimiento. Un almacenamiento en caché demasiado agresivo hace que los usuarios vean datos desactualizados. Un almacenamiento en caché demasiado débil provoca solicitudes excesivas al servidor y una carga lenta. Según Akamai (2025), optimizar Cache-Control para contenido estático reduce la carga del servidor en un 70-90% y mejora el tiempo de carga en un 40-60% para usuarios móviles.

Historia del encabezado

Cache-Control apareció en HTTP/1.1 (RFC 2616, 1999) como reemplazo de Expires. Expires tenía un problema fundamental: usaba una fecha absoluta que dependía de las zonas horarias del servidor y el cliente. Cache-Control resolvió este problema al cambiar a tiempo relativo (max-age en segundos desde el momento en que se recibe la respuesta). Más tarde, en RFC 7234 (2014), se agregaron nuevas directivas: immutable para activos estáticos, stale-while-revalidate y stale-if-error para validación diferida.

Directivas de Cache-Control

Cache-Control incluye más de 10 directivas divididas en tres grupos: directivas de solicitud (cliente → servidor), directivas de respuesta (servidor → cliente) y extensiones. En la práctica, el desarrollo móvil utiliza 6-7 directivas de respuesta principales que cubren el 95% de los escenarios de caché. Veamos cada una con ejemplos y recomendaciones.

DirectivaSignificadoEjemplo
max-ageTiempo de vida en segundos desde el momento de la respuestamax-age=3600 — 1 hora
s-maxagemax-age para caché compartida (proxy, CDN)s-maxage=86400 — 1 día para CDN
publicPermite el almacenamiento en caché a todos (incluidos proxies)public, max-age=3600
privatePermite el caché solo para el navegador/aplicaciónprivate, max-age=600
no-cacheNo usar sin validación (304 requerido)no-cache
no-storeProhibir completamente el almacenamiento en cachéno-store
must-revalidateDespués de max-age, debe revalidar con el origenmax-age=3600, must-revalidate
immutableEl recurso no cambiará (para activos estáticos versionados)max-age=31536000, immutable

max-age es la directiva más importante. Prohíbe al cliente realizar una solicitud al servidor durante el tiempo especificado. Para activos estáticos (CSS, JS, imágenes), max-age generalmente se establece de 1 día a 1 año. Para respuestas de API — de 0 segundos (datos siempre frescos) a 5-10 minutos (datos de referencia). s-maxage permite establecer diferentes tiempos de vida para CDN y navegador: la CDN almacena una copia durante 1 día, el navegador durante 1 hora.

no-cache vs no-store

Estas dos directivas a menudo se confunden. no-cache no prohíbe el almacenamiento en caché — requiere validar la copia almacenada en caché en cada uso mediante una solicitud condicional (If-Modified-Since o If-None-Match). Si el servidor responde con 304 — el cliente usa la caché. Si 200 — la actualiza. no-store, por otro lado, prohíbe completamente guardar la respuesta en cualquier caché, incluido el disco y la memoria. Use no-store solo para datos sensibles — tokens, datos de pago, documentos personales.

Cache-Control vs Expires

El encabezado Expires (HTTP/1.0) también especifica el tiempo de vida del recurso pero usa una fecha absoluta: Expires: Thu, 03 Jul 2026 12:00:00 GMT. Cache-Control max-age usa tiempo relativo desde el momento de la respuesta. La diferencia es crítica para sistemas distribuidos: si el servidor y el cliente están en diferentes zonas horarias, Expires puede interpretarse incorrectamente. Cache-Control no tiene este problema — 3600 segundos siempre son 3600 segundos.

Cuando ambos encabezados están presentes, Cache-Control tiene prioridad sobre Expires. Esto está definido en RFC 7234: “Si una respuesta incluye un campo Cache-Control con la directiva max-age, el destinatario DEBE ignorar el campo Expires.” En la práctica, se recomienda no devolver Expires en absoluto para clientes modernos, ya que Cache-Control cubre todos los escenarios de Expires. Sin embargo, para compatibilidad con proxies y navegadores antiguos, se pueden devolver ambos encabezados.

Expires ha sobrevivido principalmente para contenido estático en Nginx y Apache — estos servidores agregan automáticamente ambos encabezados. Si su proyecto encuentra Expires sin Cache-Control, reemplácelo por Cache-Control con max-age: la precisión del control de caché mejora y se elimina la dependencia de la zona horaria. Para la migración, basta con configurar el servidor para que agregue Cache-Control en lugar de Expires.

nginx
# Nginx: Cache-Control para archivos estáticos
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
    add_header Cache-Control "public, immutable, max-age=2592000";
}

# Diferentes políticas para diferentes tipos de contenido
location /api/config {
    expires -1;
    add_header Cache-Control "no-cache, must-revalidate";
}

location /api/static-data {
    expires 5m;
    add_header Cache-Control "public, max-age=300";
}

En la configuración de Nginx, los archivos estáticos (CSS, JS, imágenes) se configuran con Cache-Control durante 30 días con el atributo immutable — este atributo le indica al navegador que el recurso nunca cambia en esta URL (versionado mediante hash en el nombre del archivo). Los endpoints de API usan no-cache para datos dinámicos y public con un max-age corto para datos de referencia — listas solicitadas con frecuencia y que raramente cambian.

Caché en aplicaciones móviles

En las aplicaciones móviles, Cache-Control juega un papel especial debido a las limitaciones de las redes móviles: alta latencia, conexión inestable, límites de tráfico. Un almacenamiento en caché adecuado permite mostrar los datos al usuario al instante, incluso sin conexión, y actualizarlos en segundo plano. OkHttp en Android y URLSession en iOS tienen sistemas de caché integrados que respetan Cache-Control.

OkHttp usa CacheInterceptor, que lee Cache-Control de la respuesta y gestiona automáticamente el almacenamiento en caché. Si el servidor devolvió Cache-Control: max-age=3600, OkHttp no realizará una solicitud al servidor durante una hora. Después de que expire max-age, OkHttp envía una solicitud condicional con If-Modified-Since e If-None-Match. Configuración de caché en OkHttp: OkHttpClient.Builder().cache(Cache(directory, maxSize)).

kotlin
fun createCachedClient(cacheDir: File): OkHttpClient {
    return OkHttpClient.Builder()
        .cache(Cache(cacheDir, 10L * 1024 * 1024))
        .addNetworkInterceptor { chain ->
            val response = chain.proceed(chain.request())
            response.newBuilder()
                .header("Cache-Control",
                    "public, max-age=300")
                .removeHeader("Pragma")
                .build()
        }
        .build()
}

El código crea un OkHttpClient con una caché de 10 MB y anula Cache-Control a través de NetworkInterceptor. Si el servidor no devuelve Cache-Control o usa Expires, el interceptor agrega public, max-age=300 (5 minutos). El interceptor elimina el obsoleto encabezado Pragma (HTTP/1.0) para compatibilidad. El almacenamiento en caché en iOS funciona de manera similar a través de URLCache.shared con las configuraciones memoryCapacity y diskCapacity.

Modo sin conexión y stale-while-revalidate

La directiva stale-while-revalidate permite mostrar al usuario una caché obsoleta mientras la aplicación obtiene datos nuevos en segundo plano. Esto proporciona un efecto de respuesta instantánea: el usuario ve el contenido de inmediato y, después de un segundo, se actualiza a la versión actual. Compatible con OkHttp a partir de la versión 3.10 y URLCache en iOS 14+. Ejemplo: Cache-Control: max-age=3600, stale-while-revalidate=300 — 1 hora de caché actualizada, luego 5 minutos de mostrar datos obsoletos con actualización en segundo plano.

Ejemplos de configuración de Cache-Control

Diferentes tipos de recursos requieren diferentes estrategias de almacenamiento en caché. Veamos las configuraciones óptimas para escenarios típicos en el desarrollo móvil. Para contenido estático con un hash en el nombre del archivo (bundle.abc123.js), puede establecer max-age hasta 1 año con immutable. Para listas de API que se actualizan raramente (directorios, categorías) — max-age de 5 minutos a 1 hora con stale-while-revalidate.

Tipo de recursoCache-ControlExplicación
Activos estáticos versionadospublic, max-age=31536000, immutable1 año, los archivos no cambian (hash en URL)
Activos estáticos no versionadospublic, max-age=86400, must-revalidate1 día con revalidación forzada después
API: datos de referenciapublic, max-age=600, stale-while-revalidate=6010 minutos de caché + 1 minuto obsoleto
API: datos de usuarioprivate, max-age=601 minuto, solo para un usuario específico
API: datos sensiblesno-storeProhibición completa de caché
Páginas HTMLno-cache, must-revalidateValidación en cada solicitud, 304 si no ha cambiado

Es importante recordar la seguridad: para las respuestas que contienen datos personales del usuario, siempre establezca private. Sin esta directiva, un proxy público (por ejemplo, corporativo) puede almacenar en caché la respuesta y entregarla a otro usuario. Para tokens de autenticación e información de pago, use no-store — ni siquiera una caché privada debe almacenar estos datos en disco.

Depuración del almacenamiento en caché

Para verificar la corrección de Cache-Control, use el encabezado Age (cuántos segundos se ha almacenado la caché) y X-Cache (hit/miss en CDN). En el navegador — la pestaña Network, la columna Size muestra “from disk cache” o “304 Not Modified”. Si un recurso debería almacenarse en caché pero se carga cada vez, verifique si el servidor está agregando Cache-Control: no-cache o Pragma: no-cache junto con sus directivas.

Preguntas frecuentes

¿Cuál es la diferencia entre max-age y s-maxage?

max-age se aplica a todas las cachés (incluidos los navegadores), s-maxage solo se aplica a las cachés compartidas (proxies, CDN). Si se especifica s-maxage, la CDN ignora max-age y usa s-maxage. Esto permite establecer diferentes tiempos de vida para el navegador y la CDN.

¿Se puede cancelar el almacenamiento en caché después de enviar Cache-Control?

No, después de enviar una respuesta con max-age, el cliente no realizará una solicitud hasta que expire el temporizador. Para una invalidación inmediata de la caché, debe cambiar la URL del recurso (agregar una versión/hash) y enviar notificaciones push o mensajes WebSocket para un restablecimiento forzado.

¿Qué es la directiva immutable?

La directiva immutable (RFC 8246) le indica al navegador que el recurso nunca cambiará en esta URL. El navegador ni siquiera intenta realizar una solicitud condicional al actualizar la página — usa la caché hasta que expire max-age. Funciona solo con archivos versionados.

¿Cómo afecta Cache-Control al SEO?

Googlebot tiene en cuenta Cache-Control: un almacenamiento en caché prolongado acelera el rastreo repetido. noindex con caché rápido está bien. no-store puede ralentizar la indexación porque Googlebot cargará la página desde cero cada vez. Un max-age demasiado corto aumenta la carga del servidor durante el rastreo.

¿Cómo configurar Cache-Control en Express.js?

A través de helmet o middleware: res.set('Cache-Control', 'public, max-age=3600'). Para archivos estáticos, use express.static con el parámetro maxAge: express.static('public', {maxAge: '1y'}). Para rutas dinámicas — individualmente en cada manejador.

Resumen

  • Cache-Control — el principal encabezado HTTP para la gestión de caché con un sistema flexible de directivas
  • max-age — tiempo de vida en segundos desde el momento de la respuesta; directiva clave para todos los escenarios de caché
  • private vs public — private solo para el cliente, public para proxies y CDN; afecta la seguridad de los datos
  • no-cache requiere validación, no-store prohíbe completamente el caché; diferentes propósitos, no confundir
  • s-maxage — anula max-age para cachés compartidos, útil para dividir políticas de navegador/CDN
  • stale-while-revalidate — muestra caché obsoleta con actualización en segundo plano para UX instantáneo
  • Recomendación — configurar Cache-Control para cada tipo de recurso en el servidor y en el cliente HTTP móvil

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también