gzip, Brotli y Zstandard
Qué diferencia técnicamente a los tres algoritmos, cuánto mejora cada uno sobre el anterior, y cuál elegir para cada situación de servidor y de contenido.
Tres algoritmos conviven hoy en la web y no compiten en el mismo eje. gzip es el mínimo común denominador con casi treinta años de despliegue. Brotli comprime mejor el texto que ningún otro gracias a un truco específico para la web. Zstandard descomprime mucho más rápido que ambos y ofrece un rango de compromisos más amplio. Elegir bien exige saber qué optimiza cada uno.
- Enumerar las diferencias técnicas entre los tres algoritmos.
- Cuantificar la mejora de Brotli sobre gzip y el compromiso de Zstandard.
- Configurar la negociación de codificación en un servidor real.
- Elegir el algoritmo según el tipo de contenido y el patrón de servicio.
Las tres piezas
gzip implementa el algoritmo DEFLATE, que combina sustitución de repeticiones con codificación de Huffman. Su parámetro determinante es la ventana de búsqueda de 32 KB: solo puede referenciar repeticiones que hayan ocurrido en los últimos 32 kilobytes. Tiene niveles del 1 al 9. Se identifica en la cabecera de codificación como gzip, y está soportado universalmente desde los años noventa.
Brotli usa una estructura similar con tres mejoras sustanciales. Primera, una ventana mucho mayor, configurable hasta 16 megabytes, con lo que puede referenciar repeticiones muy lejanas. Segunda, un modelado de contexto más sofisticado en la codificación por entropía. Y tercera, la característica que lo hace especial para la web: un diccionario estático incorporado de más de trece mil cadenas frecuentes en HTML, CSS y JavaScript, extraído de un corpus real de la web. Eso significa que cadenas como <!DOCTYPE html> o function ya están en el diccionario y cuestan una referencia corta desde la primera aparición, sin necesidad de haber aparecido antes en el archivo. Tiene niveles del 0 al 11. Se identifica como br.
Zstandard es un diseño más reciente centrado en un objetivo distinto: velocidad de descompresión muy alta y constante, prácticamente independiente del nivel usado al comprimir. Tiene niveles del 1 al 22, y además niveles negativos hasta el -7 para modos ultrarrápidos. Se identifica como zstd, y su soporte en navegadores llegó en 2024: Chrome desde la versión 123 y Firefox desde la 126.
Qué mejora cada uno
Las cifras que siguen son órdenes de magnitud sobre contenido web típico. Los valores exactos dependen mucho del archivo concreto.
| Característica | gzip | Brotli | Zstandard |
|---|---|---|---|
| Ventana máxima | 32 KB | Hasta 16 MB | Hasta 2 GB, configurable |
| Diccionario incorporado | No | Sí, orientado a la web | No |
| Niveles | 1-9 | 0-11 | -7 a 22 |
| Ratio en texto web al máximo nivel | Referencia | 15-25% mejor | Similar a Brotli |
| Velocidad de compresión al máximo | Referencia | Mucho más lenta | Más rápida que Brotli |
| Velocidad de descompresión | Rápida | Similar a gzip | Notablemente más rápida |
| Soporte en navegadores | Universal | Universal desde 2017 | Chrome 123 y Firefox 126 en adelante |
Dos observaciones que cambian la decisión.
La ventaja de Brotli sobre gzip es mayor en archivos pequeños, precisamente por el diccionario incorporado. En un archivo de 2 KB, gzip apenas ha tenido tiempo de aprender repeticiones, mientras que Brotli ya está referenciando su diccionario desde el primer byte. En archivos grandes la diferencia se estrecha porque gzip acaba aprendiendo las repeticiones por su cuenta.
La ventaja de Zstandard no está en el ratio sino en el coste. A ratio comparable con Brotli, comprime bastante más rápido, lo cual importa mucho en contenido dinámico que se comprime en cada petición. Y descomprime mucho más rápido, lo cual importa en dispositivos móviles de gama baja donde descomprimir un bundle grande cuesta milisegundos apreciables de CPU.
Los navegadores no incluyen br en la cabecera de codificaciones aceptadas cuando la conexión no es segura. La razón es de robustez frente a intermediarios que corrompen contenido con codificaciones que no conocen. En la práctica no es una limitación, porque cualquier sitio moderno sirve por HTTPS, pero explica por qué en un entorno de desarrollo sin certificado puedes ver que Brotli no se usa aunque esté configurado.
La negociación
El cliente anuncia lo que acepta y el servidor elige:
Accept-Encoding: gzip, deflate, br, zstd
Y responde declarando lo que ha usado:
Content-Encoding: br
Vary: Accept-Encoding
La cabecera Vary es obligatoria aquí. Sin ella, una caché compartida podría almacenar la respuesta comprimida con Brotli y servírsela a un cliente que solo acepta gzip, que recibiría bytes ilegibles.
Configuración en nginx con los tres algoritmos, sirviendo archivos precomprimidos cuando existan y comprimiendo al vuelo cuando no:
# Tipos comprimibles, compartidos por los tres modulos.
gzip_types
text/plain text/css text/xml text/javascript
application/javascript application/json application/xml
application/wasm image/svg+xml
font/ttf font/otf application/vnd.ms-fontobject;
# gzip: respaldo universal.
gzip on;
gzip_comp_level 6;
gzip_min_length 256;
gzip_vary on;
gzip_static on; # sirve fichero.gz si existe
# Brotli: preferido cuando el cliente lo acepta.
brotli on;
brotli_comp_level 5;
brotli_min_length 256;
brotli_static on; # sirve fichero.br si existe
brotli_types text/plain text/css application/javascript
application/json image/svg+xml application/wasm;
# Zstandard: si tu compilacion incluye el modulo.
zstd on;
zstd_comp_level 9;
zstd_min_length 256;
zstd_static on;
Tres detalles de esta configuración importan.
La directiva de longitud mínima evita comprimir respuestas diminutas. Comprimir 80 bytes no ahorra nada y el resultado puede ser mayor que el original. Un umbral entre 256 y 1.024 bytes es razonable.
Las directivas de servicio estático hacen que, si existe un archivo precomprimido junto al original, se sirva directamente sin gastar CPU. Es la base de la estrategia de precompresión.
Y el orden de preferencia lo decide el servidor, no el cliente. La cabecera del cliente puede llevar factores de calidad, pero en la práctica los navegadores no expresan preferencia y el servidor elige. La preferencia razonable es Zstandard o Brotli si el cliente los acepta, y gzip como respaldo.
Cuál elegir
La decisión depende de dos ejes: si el contenido es estático o dinámico, y de dónde te duele el coste.
Contenido estático que se comprime en el build. Usa Brotli al máximo nivel. El tiempo de compresión lo pagas una vez en integración continua y no le importa a nadie; lo que se optimiza es el tamaño transferido. Genera también una versión gzip para los clientes que no acepten Brotli, aunque hoy son casi ninguno.
Contenido dinámico generado por petición. Aquí el coste de CPU es por respuesta y sí importa. Brotli en nivel medio, entre 4 y 6, o Zstandard en nivel medio si tu servidor lo soporta. El nivel máximo de Brotli en contenido dinámico es un error caro: multiplica el tiempo de compresión por un factor grande para ganar unos pocos puntos porcentuales de tamaño.
Contenido que se descomprime en dispositivos débiles. Si sirves bundles grandes a móviles de gama baja, la velocidad de descompresión de Zstandard es un argumento real. Descomprimir un megabyte no es gratis en un procesador modesto.
Compatibilidad máxima. gzip sigue siendo el respaldo obligatorio, y debe existir siempre. El coste de mantenerlo es cero.
El número que circula, un quince o veinte por ciento mejor, se obtiene midiendo archivos grandes, típicamente un bundle de JavaScript de varios cientos de kilobytes, que es el que todo el mundo mira. Y en ese archivo la mejora es efectivamente modesta, porque gzip ya ha aprendido las repeticiones y el diccionario incorporado de Brotli aporta poco en proporción. Donde Brotli gana de verdad es en los archivos pequeños, donde el diccionario actúa desde el primer byte y gzip todavía no ha aprendido nada: en un fragmento de HTML de dos kilobytes o en una respuesta de API corta, la diferencia puede ser del treinta o cuarenta por ciento. Y resulta que los archivos pequeños son la mayoría de las respuestas de una aplicación moderna, y en particular los son las respuestas de API que se piden después de la carga, que es donde vive el tráfico real. Si evalúas Brotli midiendo solo tu bundle vas a concluir que la ganancia no compensa el cambio; si lo evalúas sobre la distribución completa de tamaños de respuesta de tu tráfico real, la conclusión suele ser la contraria.