Comparez ZSTD, Brotli et GZIP pour les APIs : vitesse, ratio de compression, coût CPU et choix pratiques par défaut pour les payloads JSON et binaires en production.

La compression des réponses d'API signifie que votre serveur encode le corps de la réponse (souvent du JSON) en un flux d'octets plus petit avant de l'envoyer sur le réseau. Le client (navigateur, application mobile, SDK ou un autre service) le décompresse ensuite. Sur HTTP, cela se négocie via des en-têtes comme Accept-Encoding (ce que le client accepte) et Content-Encoding (ce que le serveur a choisi).
La compression vous apporte principalement trois choses :
Le compromis est simple : la compression économise de la bande passante mais coûte du CPU (compression/décompression) et parfois de la mémoire (buffers). La pertinence dépend de votre goulot d'étranglement.
La compression brille généralement quand les réponses sont :
Si vous renvoyez de grandes listes JSON (catalogues, résultats de recherche, analytics), la compression est souvent l'un des gains les plus faciles à obtenir.
La compression est souvent une mauvaise utilisation du CPU quand les réponses sont :
Quand vous choisissez entre ZSTD vs Brotli vs GZIP pour la compression d'API, la décision pratique se résume souvent à :
Tout le reste dans cet article concerne l'équilibre de ces trois éléments selon votre API et vos patterns de trafic.
Les trois réduisent la taille du payload, mais optimisent pour des contraintes différentes — vitesse, ratio ou compatibilité.
Vitesse ZSTD : excellent quand votre API est sensible à la latence tail ou que vos serveurs sont liés au CPU. Il peut compresser assez vite pour que le surcoût soit négligeable face au temps réseau — surtout pour les réponses JSON moyennes à grandes.
Ratio Brotli : meilleur quand la bande passante est la contrainte principale (clients mobiles, egress coûteux, livraison via CDN) et que les réponses sont majoritairement textuelles. Les petits payloads peuvent en valoir la peine même si la compression prend plus de temps.
Compatibilité GZIP : meilleur quand vous avez besoin du support client maximal sans risque de négociation (SDK anciens, clients embarqués, proxies legacy). C'est un baseline sûr même s'il n'est pas le plus performant.
Les « niveaux » de compression sont des presets qui font échanger temps CPU contre taille de sortie :
La décompression est généralement beaucoup moins coûteuse que la compression pour les trois formats, mais des niveaux très élevés peuvent encore augmenter la consommation CPU/batterie côté client — important pour le mobile.
La compression est souvent vendue comme « réponses plus petites = APIs plus rapides ». C'est souvent vrai sur des réseaux lents ou coûteux — mais ce n'est pas automatique. Si la compression ajoute suffisamment de temps CPU côté serveur, vous pouvez obtenir des requêtes plus lentes malgré moins d'octets envoyés.
Il est utile de séparer deux coûts :
Un fort ratio de compression peut réduire le temps de transfert, mais si la compression ajoute (par exemple) 15–30 ms de CPU par réponse, vous pouvez perdre plus de temps que vous n'en gagnez — surtout sur les connexions rapides.
Sous charge, la compression peut nuire davantage à la latence p95/p99 que p50. Quand l'utilisation CPU monte, les requêtes font la queue. La mise en file amplifie de petits coûts par requête en gros délais — la latence moyenne peut rester correcte, mais les utilisateurs les plus lents en pâtissent.
Ne devinez pas. Faites un test A/B ou un déploiement progressif et comparez :
Testez avec des patterns de trafic et des payloads réalistes. Le « meilleur » niveau de compression est celui qui réduit le temps total, pas seulement les octets.
La compression n'est pas “gratuite” — elle transfère du travail du réseau vers le CPU et la mémoire des deux côtés. Dans les APIs, cela se traduit par un temps de traitement par requête plus élevé, une empreinte mémoire plus grande et parfois des ralentissements côté client.
La plupart du CPU est consommée en compressant les réponses. La compression cherche des motifs, construit des états/dictionnaires et écrit la sortie encodée.
La décompression est typiquement moins coûteuse, mais reste pertinente :
Si votre API est déjà liée au CPU (serveurs d'apps très sollicités, authentifications lourdes, requêtes coûteuses), activer un niveau élevé de compression peut augmenter la latence tail même si les payloads rétrécissent.
La compression peut augmenter l'utilisation mémoire :
Dans des environnements conteneurisés, des pics mémoire plus élevés peuvent se traduire par des OOM kills ou des limites plus strictes réduisant la densité.
La compression ajoute des cycles CPU par réponse, réduisant le débit par instance. Cela peut déclencher l'autoscaling plus tôt, augmentant les coûts. Un schéma courant : bande passante en baisse, mais dépense CPU en hausse — le bon choix dépend de la ressource qui vous manque.
Sur mobile ou appareils peu puissants, la décompression rivalise avec le rendu, l'exécution JS et la batterie. Un format qui sauve quelques Ko mais prend plus de temps à décompresser peut sembler plus lent, surtout quand le “temps jusqu'aux données utilisables” compte.
Zstandard (ZSTD) est un format moderne conçu pour offrir un bon ratio de compression sans ralentir votre API. Pour de nombreuses APIs riches en JSON, c'est un excellent « par défaut » : réponses nettement plus petites que GZIP pour une latence comparable ou inférieure, et une décompression très rapide côté client.
ZSTD est précieux quand vous vous souciez du temps de bout en bout, pas seulement des octets. Il compresse rapidement et décompresse extrêmement vite — utile pour des APIs où chaque milliseconde CPU concurrence le traitement de la requête.
Il fonctionne bien sur un large éventail de tailles de payload : JSON petit à moyen voit souvent des gains, et les grandes réponses profitent encore plus.
Pour la plupart des APIs, commencez par des niveaux bas (généralement 1–3). Ils offrent souvent le meilleur compromis latence/taille.
Augmentez les niveaux seulement quand :
Approche pragmatique : un défaut global bas, puis augmenter sélectivement le niveau pour quelques endpoints qui renvoient de grosses réponses.
ZSTD supporte le streaming, ce qui peut réduire la mémoire maximale et commencer l'envoi plus tôt pour les grandes réponses.
Le mode dictionnaire peut être un grand gain pour des APIs qui retournent beaucoup d'objets similaires (clés répétées, schémas stables). C'est efficace quand :
Le support côté serveur est simple dans de nombreux écosystèmes, mais la compatibilité client peut décider du choix. Certains clients HTTP, proxies et gateways n'annoncent ou n'acceptent pas Content-Encoding: zstd par défaut.
Si vous servez des consommateurs tiers, gardez un fallback (généralement GZIP) et n'activez ZSTD que lorsque Accept-Encoding l'inclut clairement.
Brotli est conçu pour compresser très efficacement le texte. Sur JSON, HTML et autres payloads « verbeux », il bat souvent GZIP sur le ratio — surtout à des niveaux élevés.
Les réponses textuelles sont le terrain de prédilection de Brotli. Si votre API envoie de gros documents JSON (catalogues, résultats de recherche, blobs de configuration), Brotli peut réduire sensiblement les octets, ce qui aide sur réseaux lents et réduit le coût d'egress.
Brotli est aussi fort quand vous pouvez compresser une fois et servir beaucoup (réponses cacheables, ressources versionnées). Dans ce cas, Brotli en haut niveau peut valoir le coût CPU car il est amorti.
Pour les réponses dynamiques générées à chaque requête, les meilleurs ratios de Brotli demandent souvent des niveaux élevés coûteux en CPU et qui augmentent la latence. Une fois le temps de compression pris en compte, le gain réel sur ZSTD (ou même un GZIP bien réglé) peut être plus petit que prévu.
Il est aussi moins pertinent pour les payloads qui ne se compressent pas bien (données déjà compressées, formats binaires), où vous brûlez du CPU pour peu de résultat.
Les navigateurs supportent généralement bien Brotli en HTTPS, ce qui explique sa popularité sur le trafic web. Pour des clients API non-navigateur (SDK mobiles, IoT, piles HTTP anciennes), le support peut être inégal — négociez avec Accept-Encoding et gardez un fallback (typiquement GZIP).
GZIP reste la réponse par défaut pour la compression d'API car c'est l'option la plus universellement supportée. Presque tous les clients HTTP, navigateurs, proxies et gateways comprennent Content-Encoding: gzip, et cette prévisibilité compte quand vous ne contrôlez pas entièrement les intermédiaires.
L'avantage n'est pas que GZIP soit le « meilleur » — c'est qu'il est rarement le mauvais choix. Beaucoup d'organisations ont des années d'expérience opérationnelle avec, des defaults sensés dans leurs serveurs web, et moins de surprises avec des intermédiaires qui pourraient mal gérer les encodages plus récents.
Pour les payloads API (souvent du JSON), les niveaux moyens à bas sont le meilleur compromis. Des niveaux comme 1–6 offrent la majeure partie de la réduction de taille tout en gardant le CPU raisonnable.
Les niveaux très élevés (8–9) peuvent gagner un peu plus, mais le CPU additionnel vaut rarement le coût pour un trafic dynamique où la latence compte.
Sur du matériel moderne, GZIP est généralement plus lent que ZSTD pour un ratio comparable, et il ne peut souvent pas égaler les meilleurs ratios de Brotli sur du texte. Dans des charges API réelles :
Si vous devez supporter des clients anciens, des dispositifs embarqués, des proxies d'entreprise stricts ou des gateways legacy, GZIP est le pari le plus sûr. Certains intermédiaires suppriment les encodages inconnus, ne les transmettent pas ou cassent la négociation — des problèmes beaucoup moins fréquents avec GZIP.
Si votre environnement est mixte ou incertain, commencer par GZIP (et ajouter ZSTD/Brotli pour les chemins que vous contrôlez entièrement) est souvent la stratégie de déploiement la plus fiable.
Les gains de compression ne dépendent pas seulement de l'algorithme. Le principal pilote est le type de données que vous envoyez. Certains payloads rétrécissent fortement avec ZSTD, Brotli ou GZIP ; d'autres à peine et ne font que brûler du CPU.
Les réponses riches en texte se compressent extrêmement bien parce qu'elles contiennent des clés répétées, des espaces et des motifs prévisibles.
Plus il y a de répétition et de structure, meilleur est le ratio.
Les formats binaires comme Protocol Buffers et MessagePack sont plus compacts que JSON, mais ne sont pas « aléatoires ». Ils peuvent contenir des tags répétés, des layouts de records similaires et des séquences prévisibles.
Ils sont souvent encore compressibles, en particulier pour des réponses larges ou des endpoints renvoyant des listes. La seule réponse fiable est de tester avec votre trafic réel : même endpoint, mêmes données, compression activée/désactivée, et comparez taille et latence.
Beaucoup de formats sont déjà compressés en interne. Appliquer une compression HTTP dessus donne des gains minimes et peut augmenter le temps de réponse.
Pour ces formats, il est courant de désactiver la compression selon le type de contenu.
Une approche simple est de compresser seulement quand les réponses dépassent une taille minimale :
Content-Encoding.Cela concentre le CPU sur les payloads où la compression réduit réellement la bande passante et améliore la performance bout en bout.
La compression ne fonctionne bien que lorsque clients et serveurs s'accordent sur un encodage. Cet accord se fait via Accept-Encoding (envoyé par le client) et Content-Encoding (renvoyé par le serveur).
Un client annonce ce qu'il peut décoder :
GET /v1/orders HTTP/1.1
Host: api.example
Accept-Encoding: zstd, br, gzip
Le serveur choisit un encodage et le déclare :
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: zstd
Si le client envoie Accept-Encoding: gzip et que vous répondez Content-Encoding: br, ce client risque d'échouer à parser le corps. Si le client n'envoie pas Accept-Encoding, le plus sûr est de ne pas compresser.
Un ordre pratique pour les APIs est souvent :
zstd d'abord (bon équilibre vitesse/ratio)br (souvent plus petit, parfois plus lent)gzip (compatibilité maximale)Autrement dit : zstd > br > gzip.
Ne considérez pas cela comme universel : si votre trafic est majoritairement navigateur, br peut mériter une priorité plus élevée ; si vous avez des clients mobiles anciens, gzip peut être le choix le plus sûr.
Si une réponse peut être servie avec plusieurs encodages, ajoutez :
Vary: Accept-Encoding
Sans cela, un CDN ou proxy peut mettre en cache la variante gzip (ou zstd) et la servir incorrectement à un client qui n'a pas demandé (ou ne peut pas décoder) cet encodage.
Certains clients annoncent le support mais ont des décodeurs bogués. Pour rester résilient :
zstd, rebasculer temporairement sur gzip.La négociation vise moins à gagner chaque octet qu'à ne jamais casser un client.
La compression d'API ne fonctionne pas en vase clos. Le protocole de transport, la surcharge TLS et tout CDN ou gateway entre les deux peuvent changer le résultat réel — voire casser les choses si mal configurés.
Avec HTTP/2, plusieurs requêtes partagent une connexion TCP unique. Cela réduit les coûts de connexion, mais la perte de paquets peut bloquer tous les streams à cause du head-of-line TCP. La compression aide en réduisant la quantité de données « bloquée » derrière un événement de perte.
HTTP/3 utilise QUIC (UDP) et évite le head-of-line TCP entre streams. La taille du payload reste importante, mais la pénalité de perte est souvent moins dramatique par connexion. En pratique, la compression reste utile — attendez-vous à des bénéfices davantage sur les économies de bande passante et le “time to last byte” que sur des baisses spectaculaires de latence.
TLS consomme déjà du CPU (handshakes, chiffrage/déchiffrage). Ajouter la compression (surtout à des niveaux élevés) peut vous faire franchir vos limites CPU lors de pics. C'est pourquoi des réglages de compression rapides avec un bon ratio surpassent souvent les réglages « maximum ratio » en production.
Certains CDNs/gateways compressent automatiquement certains MIME types, d'autres font passer ce que l'origine envoie. Quelques-uns peuvent normaliser ou même supprimer Content-Encoding si mal configurés.
Vérifiez le comportement par route, et assurez-vous que Vary: Accept-Encoding est préservé pour que les caches ne servent pas une variante compressée à un client qui n'en a pas la capacité.
Si vous mettez en cache en périphérie, envisagez de stocker des variantes séparées par encodage (gzip/br/zstd) plutôt que de recomprimer à chaque hit. Si vous cachez à l'origine, laissez le edge négocier et mettre en cache plusieurs encodages.
La clé est la cohérence : Content-Encoding correct, Vary correct et une responsabilité claire de qui compresse où.
Pour APIs orientées navigateur, préférez Brotli lorsque le client l'annonce (Accept-Encoding: br). Les navigateurs décodent généralement Brotli efficacement et il réduit souvent la taille sur les réponses textuelles.
Pour APIs internes service-à-service, par défaut ZSTD quand les deux côtés sont sous votre contrôle. Il est typiquement plus rapide pour un ratio égal ou meilleur que GZIP, et la négociation est simple.
Pour APIs publiques utilisées par des SDK variés, gardez GZIP comme baseline universelle et ajoutez ZSTD en opt-in pour les clients qui le supportent explicitement. Ainsi vous évitez de casser des piles HTTP anciennes.
Commencez par des niveaux faciles à mesurer et qui ne surprennent pas :
Si vous avez besoin d'un meilleur ratio, validez avec des échantillons de payloads proches de la production et suivez la p95/p99 avant d'augmenter les niveaux.
Compresser de petites réponses peut coûter plus de CPU que ça ne rapporte. Un point de départ pratique :
Ajustez en comparant : (1) octets économisés, (2) temps serveur ajouté, (3) changement de latence bout en bout.
Déployez la compression derrière un feature flag, puis ajoutez une config par route (activer pour /v1/search, désactiver pour endpoints déjà petits). Fournissez un opt-out client via Accept-Encoding: identity pour le dépannage et les clients limites. Incluez toujours Vary: Accept-Encoding pour garder les caches corrects.
Si vous générez des APIs rapidement (par ex. prototypes full‑stack rapides), la compression devient un de ces petits réglages à fort impact. Sur Koder.ai, les équipes atteignent souvent ce point tôt car elles prototypent et déploient vite, puis règlent le comportement en production (compression des réponses, headers de cache) une fois les endpoints stabilisés. Le message pratique : considérez la compression comme une fonctionnalité de performance, activez-la derrière un flag et mesurez la p95/p99 avant de déclarer la victoire.
Les changements de compression sont faciles à déployer et étonnamment faciles à casser. Traitez-les comme une feature en production : déployez progressivement, mesurez l'impact et gardez un rollback simple.
Commencez par un canary : activez le nouvel Content-Encoding (par exemple zstd) pour une petite fraction du trafic ou un client interne.
Puis montez en charge (1 % → 5 % → 25 % → 100 %), en vous arrêtant si les métriques clés bougent mal.
Préparez un rollback facile :
gzip).Traquez la compression à la fois comme changement de performance et de fiabilité :
4xx/5xx, échecs de décodage client et timeouts.Quand quelque chose casse, voici les suspects habituels :
Content-Encoding indiqué mais le corps n'est pas compressé (ou inversement)Accept-Encoding ou on renvoie un encodage que le client n'a pas annoncéContent-Length incorrect ou interférence proxy/CDNIndiquez clairement les encodages supportés dans votre doc :
Accept-Encoding: zstd, br, gzipContent-Encoding: zstd (ou fallback)Si vous fournissez des SDKs, ajoutez des exemples de décodage copy-pasteables et précisez les versions minimales pour Brotli ou Zstandard.
Utilisez la compression de réponse lorsque les réponses sont riches en texte (JSON/GraphQL/XML/HTML), de taille moyenne à grande, et que vos utilisateurs sont sur des réseaux lents/ouverts à coût élevé ou que vous payez des frais d'egress significatifs. Évitez-la (ou appliquez un seuil élevé) pour les très petites réponses, les médias déjà compressés (JPEG/MP4/ZIP/PDF) et les services liés au CPU où un travail par requête supplémentaire détériorerait le p95/p99.
Parce que la compression échange de la bande passante contre du CPU (et parfois de la mémoire). Le temps de compression peut retarder le début de l'envoi des octets (TTFB), et sous charge il peut amplifier l'enfilage des requêtes — affectant souvent la latence de queue (tail) même si la latence moyenne s'améliore. Le meilleur réglage est celui qui réduit le temps de bout en bout, pas seulement la taille utile.
Un ordre pratique par défaut pour beaucoup d'APIs :
zstd en priorité (rapide, bon ratio)br (souvent le plus petit pour le texte, peut coûter plus de CPU)gzip (compatibilité maximale)Basez toujours le choix final sur ce que le client annonce dans , et gardez un repli sûr (typiquement ou ).
Commencez bas et mesurez.
Utilisez un seuil minimum de taille de réponse pour ne pas brûler du CPU sur des petits payloads.
Réglez par endpoint en comparant les octets économisés, le temps serveur ajouté et l'impact sur la latence p50/p95/p99.
Concentrez-vous sur les types de contenu structurés et répétitifs :
La négociation doit suivre HTTP :
Accept-Encoding (ex. zstd, br, gzip)Content-Encoding qu'il sait que le client peut décoderSi le client n'envoie pas , la réponse la plus sûre est généralement . Ne renvoyez jamais un que le client n'a pas annoncé, sinon il risque d'échouer à parser le corps.
Ajoutez :
Vary: Accept-EncodingCela empêche un CDN/proxy de mettre en cache (par exemple) une réponse gzip et de la renvoyer à un client qui n'a pas demandé ou ne peut pas décoder gzip (ou zstd/br). Si vous supportez plusieurs encodages, cet en-tête est essentiel pour un bon comportement du cache.
Les modes d'échec fréquents incluent :
Déployez-le comme une fonctionnalité de performance :
Content-Encoding (par ex. zstd) pour une petite portion du traficSurveillez :
Accept-EncodinggzipidentityLes niveaux supérieurs offrent généralement des gains de taille décroissants mais peuvent crever le CPU et détériorer le p95/p99.
Une approche courante consiste à activer la compression uniquement pour des valeurs Content-Type textuelles et à la désactiver pour les formats déjà compressés.
Accept-EncodingContent-EncodingContent-Encoding indique gzip mais le corps n'est pas gzippé)Accept-Encoding)Content-Length incorrect lors du streaming/compressionPour déboguer, capturez les en-têtes bruts et vérifiez la décompression avec un client/outils de référence.
Si la latence tail augmente sous charge, baissez le niveau, augmentez le seuil, ou passez à un codec plus rapide (souvent ZSTD).