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

Buffer no Node.js: Guia Prático

Atualizado em: 30 de julho de 2026

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

JavaScript foi criado principalmente para trabalhar com texto, números e objetos. Em servidores, porém, aplicações também precisam manipular arquivos, imagens, pacotes de rede, dados compactados e conteúdo criptografado. O Buffer no Node.js representa sequências de bytes e oferece as operações necessárias para lidar com dados binários.

Um Buffer pode armazenar texto codificado, números em diferentes formatos e blocos recebidos por streams. Ele aparece em APIs de arquivos, HTTP, TCP, criptografia e compressão. Usá-lo corretamente exige atenção ao tamanho, à codificação, aos limites de leitura e à diferença entre copiar e compartilhar memória.

Neste guia, você aprenderá a criar Buffers, converter texto, ler e escrever números, comparar blocos, concatenar chunks, usar slices, trabalhar com Base64, evitar dados não inicializados e integrar Buffers a streams e APIs.

O que é Buffer?

Buffer é uma classe global do Node.js baseada em Uint8Array. Cada posição armazena um número inteiro entre 0 e 255, correspondente a um byte.

const data = Buffer.from([65, 66, 67]);

console.log(data);           // <Buffer 41 42 43>
console.log(data.toString()); // ABC

A representação hexadecimal mostra os bytes 41, 42 e 43. Ao converter para texto usando UTF-8, eles formam ABC.

A documentação oficial de Buffer detalha métodos, codificações e herança de Typed Arrays. Para revisar a base da plataforma, consulte o que é Node.js e o que é JavaScript.

Criando um Buffer a partir de texto

const buffer = Buffer.from('Código Fácil', 'utf8');

console.log(buffer.length);
console.log(buffer.toString('utf8'));

O tamanho representa bytes, não quantidade de caracteres. Letras acentuadas podem ocupar mais de um byte em UTF-8. Por isso, string.length e Buffer.byteLength() podem produzir valores diferentes.

const text = 'ação';

console.log(text.length);
console.log(Buffer.byteLength(text, 'utf8'));

Codificações suportadas

As codificações mais usadas são:

  • utf8 para texto comum;
  • utf16le para UTF-16 little-endian;
  • latin1 para um byte por caractere;
  • hex para representação hexadecimal;
  • base64 e base64url para transporte textual de bytes;
  • ascii para subconjunto ASCII.

Escolha a codificação de acordo com o protocolo ou formato. Adivinhar codificação pode produzir caracteres corrompidos sem lançar erro.

Convertendo para hexadecimal e Base64

const data = Buffer.from('Node.js');

console.log(data.toString('hex'));
console.log(data.toString('base64'));

Base64 não criptografa nem protege conteúdo. Ele apenas transforma bytes em caracteres adequados para campos textuais. Qualquer pessoa pode reverter a codificação.

const decoded = Buffer.from('Tm9kZS5qcw==', 'base64');
console.log(decoded.toString('utf8'));

Alocando memória

Buffer.alloc() cria um bloco inicializado com zeros:

const safe = Buffer.alloc(1024);

Buffer.allocUnsafe() pode ser mais rápido porque não limpa a região imediatamente:

const temporary = Buffer.allocUnsafe(1024);
temporary.fill(0);

O conteúdo inicial de allocUnsafe() não deve ser lido nem enviado antes de ser completamente sobrescrito. Caso contrário, dados antigos presentes na memória podem aparecer na saída. Use alloc() como padrão quando o ganho de desempenho não estiver comprovado.

Preenchendo um Buffer

const block = Buffer.alloc(8);
block.fill(255);

console.log(block);

fill() também aceita strings e intervalos. Confirme que o padrão não quebra um formato binário esperado.

Acessando bytes

const buffer = Buffer.from([10, 20, 30]);

console.log(buffer[0]);
buffer[1] = 99;
console.log(buffer);

Valores fora de 0 a 255 são ajustados para um byte. Valide números antes de armazená-los quando a precisão for importante.

Lendo e escrevendo números

Buffers possuem métodos para inteiros e números de ponto flutuante em diferentes ordens de bytes:

const buffer = Buffer.alloc(8);

buffer.writeUInt32BE(1000, 0);
buffer.writeUInt32LE(2000, 4);

console.log(buffer.readUInt32BE(0));
console.log(buffer.readUInt32LE(4));

BE significa big-endian e LE, little-endian. O protocolo define qual ordem deve ser usada. Ler com a ordem errada produz outro número.

Inteiros com sinal

const buffer = Buffer.alloc(2);

buffer.writeInt16BE(-120, 0);
console.log(buffer.readInt16BE(0));

Use métodos Int para valores com sinal e UInt para valores não negativos. Respeite a faixa que cabe na quantidade de bytes escolhida.

BigInt em Buffers

Valores inteiros de 64 bits podem ser lidos como BigInt:

const buffer = Buffer.alloc(8);

buffer.writeBigUInt64BE(9007199254740993n);
console.log(buffer.readBigUInt64BE());

Isso evita perda de precisão acima do limite seguro do tipo Number.

Verificando limites

Ler ou escrever além do tamanho gera erro. Antes de interpretar dados externos, confirme o comprimento mínimo:

function readHeader(buffer) {
  if (buffer.length < 8) {
    throw new Error('Cabeçalho incompleto');
  }

  return {
    version: buffer.readUInt16BE(0),
    size: buffer.readUInt32BE(2)
  };
}

Nunca confie apenas em um tamanho declarado dentro do próprio pacote. Compare com limites de negócio e com os bytes realmente disponíveis.

Concatenando Buffers

const first = Buffer.from('Código ');
const second = Buffer.from('Fácil');

const result = Buffer.concat([first, second]);
console.log(result.toString());

Concatenar repetidamente dentro de um loop pode copiar os dados muitas vezes. Em streams, acumule chunks em um array e chame Buffer.concat() uma vez, desde que o tamanho total seja limitado.

const chunks = [];
let total = 0;

stream.on('data', chunk => {
  total += chunk.length;

  if (total > MAX_SIZE) {
    stream.destroy(new Error('Conteúdo grande demais'));
    return;
  }

  chunks.push(chunk);
});

stream.on('end', () => {
  const body = Buffer.concat(chunks, total);
});

Buffer e Streams

Streams binárias entregam chunks como Buffers por padrão. Arquivos, respostas HTTP e sockets usam esse modelo. Para grandes volumes, processe cada chunk sem acumular o conteúdo inteiro.

O guia de Streams no Node.js explica backpressure, pipeline(), object mode e cancelamento.

slice() e subarray()

const original = Buffer.from([1, 2, 3, 4]);
const view = original.subarray(1, 3);

view[0] = 99;
console.log(original);

A sub-região compartilha a mesma memória. Alterar a view modifica o original. Esse comportamento evita cópia e melhora o desempenho, mas pode criar efeitos inesperados.

Quando você precisa de uma cópia independente:

const copy = Buffer.from(original.subarray(1, 3));

Copiando dados

const source = Buffer.from('Node.js');
const destination = Buffer.alloc(source.length);

source.copy(destination);
console.log(destination.toString());

copy() permite informar intervalos de origem e destino. Valide posições para não truncar silenciosamente dados importantes.

Comparando Buffers

const a = Buffer.from('abc');
const b = Buffer.from('abc');

console.log(a.equals(b));
console.log(Buffer.compare(a, b));

equals() compara conteúdo. O operador === verifica se as duas variáveis apontam para o mesmo objeto, não se possuem os mesmos bytes.

Comparação de dados sensíveis

Para hashes, assinaturas e tokens, uma comparação comum pode revelar diferenças de tempo. Use crypto.timingSafeEqual() quando os Buffers tiverem o mesmo tamanho:

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

function safeEqual(a, b) {
  if (a.length !== b.length) return false;
  return crypto.timingSafeEqual(a, b);
}

O comprimento ainda precisa ser verificado antes. Para outras práticas de segurança, consulte o artigo sobre webhooks seguros com Node.js.

Procurando conteúdo

const data = Buffer.from('abc:def:ghi');

console.log(data.indexOf(':'));
console.log(data.includes('def'));

Os métodos aceitam Buffer, string ou byte. Defina a codificação quando buscar texto não ASCII.

TypedArray e ArrayBuffer

Como Buffer herda de Uint8Array, ele pode interagir com APIs que utilizam Typed Arrays. Para compartilhar a região com outra view:

const buffer = Buffer.from([1, 2, 3, 4]);

const view = new Uint8Array(
  buffer.buffer,
  buffer.byteOffset,
  buffer.byteLength
);

Considere byteOffset e byteLength. O ArrayBuffer subjacente pode ser maior que a região visível pelo Buffer.

Recebendo dados HTTP

Ao acumular o corpo manualmente, aplique limite:

function readBody(req, maxBytes = 1_000_000) {
  return new Promise((resolve, reject) => {
    const chunks = [];
    let size = 0;

    req.on('data', chunk => {
      size += chunk.length;

      if (size > maxBytes) {
        req.destroy();
        reject(new Error('Payload excedeu o limite'));
        return;
      }

      chunks.push(chunk);
    });

    req.on('end', () => {
      resolve(Buffer.concat(chunks, size));
    });

    req.on('error', reject);
  });
}

Frameworks já oferecem parsers com limites configuráveis. Evite duplicar essa lógica sem necessidade. Para estruturar endpoints, veja como criar uma API com Node.js.

Buffers e arquivos

const fs = require('node:fs/promises');

const image = await fs.readFile('./photo.png');
console.log(Buffer.isBuffer(image));

readFile() carrega o arquivo inteiro. Para arquivos grandes ou muitos acessos simultâneos, use stream de leitura.

Limpando dados sensíveis

Quando um Buffer contém uma chave ou senha temporária, sobrescreva a região depois do uso:

const secret = Buffer.from(process.env.SECRET_KEY, 'utf8');

try {
  useSecret(secret);
} finally {
  secret.fill(0);
}

Isso reduz o tempo em que o valor permanece diretamente no bloco, embora não garanta remoção de todas as cópias criadas anteriormente.

Limites de memória

Buffers grandes consomem memória fora de parte do heap tradicional do JavaScript, mas continuam afetando o processo. Monitore process.memoryUsage(), especialmente o campo external e o uso de ArrayBuffers.

Evite aceitar um tamanho fornecido pelo usuário e chamar Buffer.alloc() sem limite. Um valor enorme pode derrubar o processo.

Testando código binário

Crie amostras pequenas com bytes conhecidos e verifique resultados em hexadecimal:

const assert = require('node:assert/strict');

const packet = Buffer.alloc(4);
packet.writeUInt16BE(1, 0);
packet.writeUInt16BE(500, 2);

assert.equal(packet.toString('hex'), '000101f4');

Inclua casos com pacote incompleto, tamanho máximo, ordem de bytes errada, caracteres multibyte e dados inválidos.

Erros comuns

  • Confundir caracteres com bytes: UTF-8 pode usar vários bytes por caractere.
  • Ler fora do limite: pacotes incompletos geram exceções.
  • Usar allocUnsafe sem sobrescrever: dados antigos podem ser expostos.
  • Achar que Base64 é criptografia: a codificação é facilmente reversível.
  • Alterar uma subarray sem perceber: a memória é compartilhada.
  • Acumular streams sem limite: payloads grandes esgotam memória.
  • Usar === para conteúdo: o operador compara referências.
  • Ignorar endianness: números são interpretados incorretamente.

Boas práticas para produção

  • Defina codificação explicitamente.
  • Use Buffer.alloc() como padrão seguro.
  • Valide tamanho antes de ler ou alocar.
  • Use streams para conteúdo grande.
  • Copie sub-regiões quando precisar de independência.
  • Use comparação de tempo constante para segredos.
  • Monitore memória externa e quantidade de buffers ativos.
  • Não registre conteúdo binário sensível em logs.
  • Teste limites, codificações e ordem de bytes.
  • Sobrescreva segredos temporários quando possível.

Conclusão

O Buffer no Node.js é a base para trabalhar com bytes em arquivos, redes, streams, criptografia e compressão. Ele permite converter codificações, interpretar números e manipular regiões de memória com alto desempenho.

A eficiência vem acompanhada de responsabilidade. Valide tamanhos, escolha a codificação correta, entenda quando a memória é compartilhada e evite acumular conteúdo ilimitado. Com esses cuidados, dados binários podem ser processados de forma segura e previsível em aplicações Node.js.

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