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

NATS no Node.js: Guia Prático

Atualizado em: 5 de setembro de 2026

Rack de servidores processando fluxos de dados no Node.js

Usar NATS no Node.js permite criar comunicação rápida entre serviços com publish/subscribe, request/reply, queue groups e persistência por JetStream. O protocolo é baseado em subjects, que funcionam como endereços hierárquicos para mensagens.

Core NATS prioriza baixa latência e entrega at-most-once, enquanto JetStream adiciona retenção, consumidores duráveis, ACK, replay e políticas de entrega. A escolha depende da importância da mensagem e da necessidade de recuperação.

Neste guia, você aprenderá conexão, subjects, publish/subscribe, request/reply, queue groups, JetStream, consumers, ACK, retries, idempotência, segurança, observabilidade e testes.

O que é NATS?

NATS é uma plataforma de mensageria distribuída. A documentação oficial para desenvolvimento com NATS apresenta conexão, envio, recebimento, serviços e JetStream. O cliente JavaScript oficial está no projeto nats.js.

Para comparar com brokers persistentes, consulte RabbitMQ com Node.js e Kafka com Node.js.

Instalação

npm install nats

Conectando

import { connect, StringCodec } from 'nats';

const nc = await connect({
  servers: process.env.NATS_SERVERS?.split(','),
  name: 'orders-api',
  maxReconnectAttempts: -1,
  reconnectTimeWait: 1000
});

const codec = StringCodec();

Em produção, use vários servidores ou uma URL descoberta pelo ambiente.

Eventos de status

(async () => {
  for await (const status of nc.status()) {
    logger.info({
      type: status.type,
      data: status.data
    }, 'Status da conexão NATS');
  }
})();

Monitore desconexão, reconexão e atualização de servidores.

Publish básico

nc.publish(
  'orders.created',
  codec.encode(JSON.stringify({
    eventId: crypto.randomUUID(),
    orderId,
    version: 1
  }))
);

Core NATS envia a mensagem aos assinantes ativos. Se não houver subscriber e não existir JetStream, a mensagem não fica armazenada.

Flush

await nc.flush();

publish() normalmente coloca dados no buffer local. flush() confirma que o servidor processou tudo enviado anteriormente, mas não garante que consumidores concluíram.

Subscribe

const subscription = nc.subscribe('orders.created');

for await (const message of subscription) {
  const event = JSON.parse(codec.decode(message.data));
  await handleOrderCreated(event);
}

O loop assíncrono termina quando a subscription é fechada ou a conexão é drenada.

Subjects

Subjects são hierárquicos:

orders.created
orders.approved
payments.authorized
inventory.reserved

Use nomes estáveis, orientados ao domínio e sem dados pessoais.

Wildcards

  • * corresponde a um token.
  • > corresponde ao restante da hierarquia.
nc.subscribe('orders.*');
nc.subscribe('events.>');

Evite subscriptions muito amplas sem limites de processamento.

Queue groups

const sub = nc.subscribe(
  'orders.created',
  { queue: 'billing-workers' }
);

Dentro do mesmo queue group, apenas um consumidor recebe cada mensagem. Grupos diferentes recebem cópias independentes.

Escalando consumidores

Várias instâncias com o mesmo queue group distribuem carga. O balanceamento não substitui idempotência: mensagens podem ser reenviadas em arquiteturas persistentes ou por retries do produtor.

Request/reply

const response = await nc.request(
  'inventory.check',
  codec.encode(JSON.stringify({ items })),
  { timeout: 1000 }
);

const result = JSON.parse(codec.decode(response.data));

NATS cria uma inbox temporária e aguarda uma resposta.

Respondendo

for await (const message of nc.subscribe('inventory.check')) {
  const input = JSON.parse(codec.decode(message.data));
  const output = await inventory.check(input.items);

  message.respond(
    codec.encode(JSON.stringify(output))
  );
}

Se não houver reply subject, respond() retorna false.

Timeouts

Request/reply sempre deve ter timeout. Uma resposta ausente não pode manter a requisição HTTP indefinidamente.

No responders

Quando nenhum serviço responde, o cliente pode receber erro específico. Diferencie indisponibilidade de timeout e resposta de negócio negativa.

Headers

import { headers } from 'nats';

const h = headers();
h.set('content-type', 'application/json');
h.set('traceparent', traceparent);
h.set('message-version', '1');

nc.publish('orders.created', data, { headers: h });

Não coloque segredos nos headers.

Payload binário

NATS transporta bytes. JSON é simples, mas Protocol Buffers, MessagePack ou Avro podem reduzir tamanho e fortalecer contratos. Versione qualquer formato.

Core NATS versus JetStream

  • Core NATS: at-most-once, baixa latência, subscribers ativos.
  • JetStream: mensagens armazenadas, consumers, ACK, replay e retenção.

Use Core para sinais efêmeros e JetStream quando a mensagem não pode ser perdida durante desconexão.

Criando contexto JetStream

const js = nc.jetstream();
const jsm = await nc.jetstreamManager();

Criando stream

await jsm.streams.add({
  name: 'ORDERS',
  subjects: ['orders.>'],
  max_age: 7 * 24 * 60 * 60 * 1_000_000_000,
  storage: 'file',
  retention: 'limits'
});

Parâmetros exatos e enums dependem da versão do cliente. Verifique a API atual antes de copiar para produção.

Publicando no JetStream

const ack = await js.publish(
  'orders.created',
  codec.encode(JSON.stringify(event)),
  {
    msgID: event.eventId
  }
);

O servidor retorna confirmação com stream e sequência. msgID pode ajudar a deduplicar publicações dentro da janela configurada.

Consumer durável

Consumers duráveis preservam estado entre reinícios. Configure:

  • durable name;
  • filter subject;
  • ack policy;
  • ack wait;
  • max deliveries;
  • delivery policy;
  • backoff.

Pull consumer

Pull consumers permitem controlar lote e backpressure:

const consumer = await js.consumers.get(
  'ORDERS',
  'billing'
);

const messages = await consumer.consume({
  max_messages: 20,
  expires: 5000
});

for await (const message of messages) {
  try {
    const event = JSON.parse(codec.decode(message.data));
    await handle(event);
    message.ack();
  } catch (error) {
    message.nak(1000);
  }
}

Confirme a sintaxe da versão instalada; a API moderna do nats.js evolui junto com JetStream.

ACK

  • ack(): processamento concluído.
  • nak(): falhou e deve ser entregue novamente.
  • term(): não deve ser reenviado.
  • working(): estende prazo durante tarefa longa.

Não faça ACK antes de concluir o efeito.

Ack wait

O prazo precisa ser maior que a duração normal do handler. Caso contrário, a mesma mensagem pode ser entregue a outro consumidor enquanto o primeiro ainda trabalha.

Max deliveries

Defina um limite para mensagens permanentemente inválidas. Depois envie para um subject de dead-letter ou gere um evento de falha.

Dead-letter

Uma estratégia:

await js.publish(
  'orders.dead-letter',
  message.data,
  {
    headers: deadLetterHeaders
  }
);

message.term();

Inclua ID original, tipo de erro, tentativas e horário, sem expor segredo.

Idempotência

JetStream oferece entrega at-least-once em cenários comuns. Consumidores devem deduplicar por eventId.

INSERT INTO processed_events (event_id)
VALUES ($1)
ON CONFLICT DO NOTHING;

Faça a deduplicação na mesma transação do efeito. Consulte Idempotência em APIs Node.js.

Outbox

Não atualize banco e publique no NATS como duas operações sem coordenação. Use outbox e um relay.

Consulte Domain Events no Node.js.

Ordenação

NATS preserva ordem por publisher e subject em condições normais, mas processamento paralelo pode concluir fora de ordem. Inclua aggregateVersion e detecte lacunas quando necessário.

Particionamento por subject

orders.customer.42.created

Colocar IDs no subject pode aumentar cardinalidade operacional e complexidade de permissões. Use somente quando a estratégia de roteamento justificar.

Serviços NATS

A infraestrutura de serviços oferece endpoints, grupos, metadata e observabilidade para request/reply. É útil para APIs internas leves, mas contratos e timeouts continuam necessários.

Drain

await nc.drain();

Drain para de aceitar novas mensagens, permite concluir mensagens em trânsito e fecha a conexão.

Shutdown de consumidor

  1. pare novas leituras;
  2. cancele fetch ou consume;
  3. aguarde handlers;
  4. faça ACK apenas de concluídos;
  5. execute drain;
  6. feche recursos.

Consulte Graceful Shutdown no Node.js.

Segurança

NATS suporta:

  • usuário e senha;
  • tokens;
  • NKEYs;
  • JWT e accounts;
  • TLS e mTLS;
  • permissões por subject.

Prefira credenciais temporárias ou arquivos protegidos e privilégio mínimo.

mTLS

Para autenticação mútua entre serviços, consulte mTLS no Node.js.

Subject permissions

Um serviço de billing pode publicar apenas respostas e assinar subjects necessários. Não use permissão global > sem necessidade.

Observabilidade

Monitore:

  • conexões;
  • reconexões;
  • mensagens e bytes;
  • latência request/reply;
  • consumer lag;
  • redeliveries;
  • ACK pendentes;
  • dead letters;
  • armazenamento do stream.

Correlation e tracing

Propague traceparent em headers e crie spans de publish e consume. Evite criar cardinalidade com eventId em métricas.

Testes

Use um servidor NATS real em container e teste:

  • publish/subscribe;
  • queue groups;
  • request/reply e timeout;
  • JetStream publish ACK;
  • consumer durável;
  • redelivery;
  • dead-letter;
  • idempotência;
  • drain.

Teste de desconexão

Interrompa o servidor, publique durante reconexão conforme a política do cliente e confirme comportamento esperado. Verifique limites de buffer.

Erros comuns

  • Core para evento crítico: mensagem é perdida sem subscriber.
  • Sem timeout: request/reply fica pendurado.
  • ACK antecipado: efeito pode não ocorrer.
  • Sem idempotência: redelivery duplica.
  • Subject desorganizado: permissões ficam difíceis.
  • Payload sem versão: consumidores quebram.
  • Ack wait curto: processamento concorrente duplica.
  • Fechar sem drain: mensagens em trânsito são perdidas.

Boas práticas

  • Escolha Core ou JetStream conscientemente.
  • Use subjects estáveis.
  • Defina timeout.
  • Controle queue groups.
  • Versione payloads.
  • Faça ACK após sucesso.
  • Implemente idempotência.
  • Use outbox.
  • Restrinja permissões.
  • Teste reconexão e redelivery.

Conclusão

Usar NATS no Node.js fornece publish/subscribe e request/reply com baixa latência. Queue groups facilitam escala horizontal, enquanto JetStream adiciona retenção e consumidores duráveis.

A confiabilidade depende de escolher o modo correto, usar timeouts, ACK, idempotência e outbox. Com segurança por subject, observabilidade e drain no shutdown, NATS oferece uma base simples para comunicação entre serviços.

10 melhores cursos de programação em 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