Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Zlib no Node.js: Guia Prático

Atualizado em: 2 de agosto de 2026

Módulo de memória ilustrando Buffer no Node.js

Compactar respostas, arquivos e mensagens reduz o volume transferido e pode economizar armazenamento. O módulo Zlib no Node.js, disponível como node:zlib, oferece implementações nativas de gzip, deflate e Brotli integradas ao sistema de streams.

Compressão troca CPU por menos bytes. Um nível alto pode reduzir um pouco mais o arquivo, mas aumentar bastante a latência. Dados já compactados, como JPEG e ZIP, raramente obtêm benefício. Também é necessário limitar a descompressão para evitar consumo excessivo de memória e ataques com arquivos compactados maliciosos.

Neste guia, você aprenderá a compactar buffers e streams, criar arquivos gzip, usar Brotli, negociar conteúdo HTTP, ajustar parâmetros, cancelar pipelines e testar integridade.

Carregando o módulo

const zlib = require('node:zlib');

A documentação oficial do módulo Zlib detalha formatos, constantes e opções. Para entender os fluxos usados pela API, consulte Streams no Node.js e Buffer no Node.js.

Compactando um Buffer com gzip

const { promisify } = require('node:util');
const gzip = promisify(zlib.gzip);

async function compressJson(data) {
  const input = Buffer.from(JSON.stringify(data));
  return gzip(input);
}

As funções baseadas em callback podem ser promisificadas. Esse padrão é adequado para conteúdo pequeno e limitado. Para grandes volumes, use streams.

Descompactando gzip

const gunzip = promisify(zlib.gunzip);

const compressed = await compressJson({ status: 'ok' });
const plain = await gunzip(compressed);

console.log(JSON.parse(plain.toString('utf8')));

Não descompacte conteúdo externo sem limite. Um arquivo pequeno pode expandir para um volume enorme.

Compactando arquivos com pipeline

const fs = require('node:fs');
const { pipeline } = require('node:stream/promises');

async function createGzip(source, destination) {
  await pipeline(
    fs.createReadStream(source),
    zlib.createGzip(),
    fs.createWriteStream(destination)
  );
}

O arquivo é processado em chunks, mantendo a memória previsível. Se uma etapa falha, pipeline() encerra as streams relacionadas.

Descompactando um arquivo

async function extractGzip(source, destination) {
  await pipeline(
    fs.createReadStream(source),
    zlib.createGunzip(),
    fs.createWriteStream(destination)
  );
}

Grave primeiro em um arquivo temporário. Somente depois da conclusão renomeie para o destino final, evitando que consumidores enxerguem conteúdo incompleto. O artigo sobre File System no Node.js apresenta gravação atômica.

Gzip, deflate e Brotli

  • gzip: amplamente compatível em HTTP e arquivos.
  • deflate: formato baseado em DEFLATE, com diferenças de encapsulamento.
  • deflateRaw: dados DEFLATE sem cabeçalho zlib.
  • Brotli: geralmente eficiente para texto web, com custo configurável.

O formato deve ser conhecido pelas duas partes. Não tente adivinhar apenas pela extensão.

Usando Brotli

const brotliCompress = promisify(zlib.brotliCompress);
const brotliDecompress = promisify(zlib.brotliDecompress);

const compressed = await brotliCompress(
  Buffer.from('conteúdo repetitivo')
);

const original = await brotliDecompress(compressed);

Brotli possui níveis de qualidade mais altos, mas configurações máximas podem ser muito lentas para respostas dinâmicas.

Ajustando gzip

const gzipStream = zlib.createGzip({
  level: zlib.constants.Z_BEST_SPEED
});

Z_BEST_SPEED prioriza velocidade; Z_BEST_COMPRESSION prioriza tamanho. O valor padrão costuma ser um bom equilíbrio. Meça com dados reais.

Ajustando Brotli

const brotli = zlib.createBrotliCompress({
  params: {
    [zlib.constants.BROTLI_PARAM_QUALITY]: 4
  }
});

Para assets estáticos gerados no build, um nível maior pode fazer sentido. Para respostas dinâmicas, níveis moderados reduzem CPU e tempo até o primeiro byte.

Compressão em uma resposta HTTP

const http = require('node:http');

http.createServer((req, res) => {
  const accepts = req.headers['accept-encoding'] || '';
  const body = Buffer.from(JSON.stringify({ message: 'Olá' }));

  res.setHeader('content-type', 'application/json');
  res.setHeader('vary', 'accept-encoding');

  if (accepts.includes('br')) {
    res.setHeader('content-encoding', 'br');
    zlib.brotliCompress(body, (error, output) => {
      if (error) return res.destroy(error);
      res.end(output);
    });
    return;
  }

  if (accepts.includes('gzip')) {
    res.setHeader('content-encoding', 'gzip');
    zlib.gzip(body, (error, output) => {
      if (error) return res.destroy(error);
      res.end(output);
    });
    return;
  }

  res.end(body);
}).listen(3000);

O cabeçalho Vary evita que caches entreguem uma versão compactada a clientes incompatíveis.

Nem toda resposta deve ser compactada

Evite compactar conteúdo pequeno, já compactado ou sensível quando a resposta também inclui dados controlados pelo atacante. Ataques de compressão podem explorar diferenças de tamanho para inferir segredos.

Defina um tamanho mínimo, tipos permitidos e política para respostas com tokens ou dados refletidos.

Compressão em frameworks

Frameworks oferecem middlewares que negociam Accept-Encoding, definem threshold e tratam headers. Mesmo assim, confirme a configuração do proxy, pois CDN ou servidor frontal pode realizar compressão novamente.

Evite compressão dupla

Se a aplicação envia Content-Encoding: gzip, o proxy não deve compactar outra vez. Compressão dupla gera conteúdo inválido ou desperdício. Inspecione os headers no cliente final.

Descompressão automática

Alguns clientes HTTP descompactam respostas automaticamente e removem ou preservam headers de maneiras diferentes. Não compare apenas o tamanho do Buffer recebido sem saber o comportamento da biblioteca.

Protegendo contra expansão excessiva

Ao receber conteúdo compactado, limite bytes de entrada, bytes descompactados e tempo. Uma Transform de contagem pode interromper o pipeline:

const { Transform } = require('node:stream');

function limitBytes(maxBytes) {
  let total = 0;

  return new Transform({
    transform(chunk, encoding, callback) {
      total += chunk.length;

      if (total > maxBytes) {
        callback(new Error('Conteúdo descompactado excedeu o limite'));
        return;
      }

      callback(null, chunk);
    }
  });
}
await pipeline(
  source,
  zlib.createGunzip(),
  limitBytes(50 * 1024 * 1024),
  destination
);

Cancelamento

const controller = new AbortController();

await pipeline(
  fs.createReadStream(source),
  zlib.createGzip(),
  fs.createWriteStream(destination),
  { signal: controller.signal }
);

Ao cancelar, remova o arquivo parcial. Consulte AbortController no Node.js.

Concorrência e CPU

Muitas compressões simultâneas aumentam CPU e latência. Limite concorrência, use cache para respostas repetidas e pré-comprima assets estáticos. Monitore duração e tamanho antes e depois.

Cache de versões compactadas

Para conteúdo estável, armazene versões .gz e .br no build ou na CDN. A aplicação apenas escolhe o arquivo adequado, evitando compressão a cada requisição.

Integridade

Gzip possui verificação interna, mas isso não substitui autenticação criptográfica quando o conteúdo precisa ser protegido contra alteração maliciosa. Para hashes e assinaturas, veja Crypto no Node.js.

Testando

Teste round-trip, arquivos vazios, conteúdo incompressível, dados corrompidos, cancelamento, limite excedido e concorrência. Confirme headers HTTP com e sem suporte a Brotli e gzip.

Erros comuns

  • Usar nível máximo em respostas dinâmicas.
  • Compactar JPEG, ZIP ou vídeo sem medir.
  • Esquecer Vary: Accept-Encoding.
  • Permitir descompressão sem limite.
  • Compactar duas vezes no proxy e na aplicação.
  • Carregar arquivo enorme antes de compactar.
  • Não remover destino parcial após falha.
  • Ignorar custo de CPU sob concorrência.

Boas práticas

  • Use streams para conteúdo grande.
  • Meça taxa de compressão e duração.
  • Defina threshold para respostas HTTP.
  • Prefira níveis moderados em tempo real.
  • Pré-comprima assets estáticos.
  • Limite expansão e tempo de descompressão.
  • Configure Vary corretamente.
  • Evite compressão dupla.
  • Controle concorrência.
  • Teste conteúdo corrompido.

Conclusão

O Zlib no Node.js integra gzip, deflate e Brotli ao modelo de streams. Ele permite compactar arquivos e respostas com memória previsível e configuração de desempenho.

O melhor resultado vem de medir. Escolha formato e nível conforme o tipo de conteúdo, limite descompressão e evite trabalho duplicado com proxy ou CDN. Com pipelines e observabilidade, a compressão reduz bytes sem transformar CPU em um novo gargalo.

Os 10 Melhores Cursos de Programação de 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita