NATS Reference: Pub/Sub, JetStream Streams, KV Store, Clustering & Request/Reply
NATS is a lightweight, high-performance messaging system — simpler than Kafka/RabbitMQ for most use cases. It supports pub/sub, request/reply, queue groups, and JetStream (persistent, ordered streams with at-least-once delivery).
1. NATS vs Kafka vs RabbitMQ
When to choose NATS
| Feature | NATS | Kafka | RabbitMQ |
|---|---|---|---|
| Persistence | JetStream (optional) | Always (append-only log) | Durable queues |
| Protocol | NATS native (TCP, WebSocket) | Kafka binary protocol | AMQP |
| Resource usage | Very low (~10MB server) | High (JVM, ZooKeeper/KRaft) | Medium (Erlang) |
| Latency | Sub-millisecond | Single-digit ms | Low ms |
| Core pattern | Pub/Sub, Request/Reply, Queue Groups | Consumer group offset | Exchange + queue routing |
| Clustering | Built-in (Raft, 3+ nodes) | Kafka native or KRaft | RabbitMQ clustering |
| Best for | Microservice RPC, IoT, low-overhead pub/sub | Event streaming, audit logs | Task queues, complex routing |
# Rule of thumb: # NATS: you want fast pub/sub or request/reply with minimal ops overhead # Kafka: you need event replay, large-scale streaming, or audit logs # RabbitMQ: you need dead-letter queues, complex routing, or traditional task queues
2. Core Messaging Patterns
Pub/sub, request/reply, and queue groups
# nats CLI (install: brew install nats-io/nats-tools/nats):
nats sub "orders.>" # subscribe to all orders.* subjects
nats pub orders.created '{"id": 123}' # publish
nats req orders.validate '{"id": 123}' # request/reply (waits for response)
# Subject naming:
# "." = separator (hierarchical)
# "*" = one token wildcard: orders.*.created matches orders.us.created
# ">" = multi-token wildcard: orders.> matches everything under orders
# Pub/Sub (fire and forget, no persistence):
# Publisher sends to a subject
# All subscribers to that subject receive a copy (fanout)
# No persistence — if subscriber is offline, message is lost
# Request/Reply (synchronous pattern):
# Requester publishes to a subject + sets reply-to header
# Responder receives, publishes response to reply-to address
# Used for microservice RPC without a gateway
# Queue Groups (competing consumers — like Kafka consumer groups):
# Multiple subscribers with same queue group → each message delivered to ONLY ONE
nats sub --queue mygroup orders.created # subscriber 1
nats sub --queue mygroup orders.created # subscriber 2
nats pub orders.created '{"id": 1}' # delivered to either subscriber 1 OR 2
3. JetStream — Persistent Messaging
Streams, consumers, and at-least-once delivery
# JetStream adds persistence to NATS (disabled by default — enable in server config) # nats-server --jetstream # Create a stream (like a Kafka topic): nats stream add ORDERS --subjects "orders.>" \ # capture all orders.* subjects --retention limits \ # keep until limits reached --max-age 24h \ # messages expire after 24h --storage file \ # file (disk) or memory --replicas 3 # replicate across 3 nodes # Or via YAML: nats stream add ORDERS --config stream-config.yaml # Consumer types: # Push consumer: NATS pushes messages to subscriber (like pub/sub but with ack) # Pull consumer: subscriber explicitly requests batches (like Kafka) # Create a durable pull consumer: nats consumer add ORDERS my-consumer --pull --deliver all \ # start from beginning --ack explicit # must ack each message # Pull messages: nats consumer next ORDERS my-consumer --count 10 # pull 10 messages # Push consumer (messages delivered automatically): nats consumer add ORDERS push-consumer --deliver all --ack explicit --target notifications.orders # deliver to this subject # List streams and consumers: nats stream ls nats stream info ORDERS nats consumer ls ORDERS nats consumer info ORDERS my-consumer
4. Key-Value Store (JetStream KV)
Distributed KV with watch and history
# JetStream includes a KV store backed by streams # Great for: config management, feature flags, service discovery # Create a KV bucket: nats kv add CONFIG --ttl 24h --history 5 # 5 revisions history, 24h TTL # Basic ops: nats kv put CONFIG app.log_level "info" nats kv get CONFIG app.log_level nats kv del CONFIG app.log_level nats kv ls CONFIG # list all keys nats kv history CONFIG app.log_level # show all revisions # Watch for changes (blocks until key changes): nats kv watch CONFIG app.log_level # watch one key nats kv watch CONFIG # watch all keys # Compare-and-set (atomic update): nats kv update CONFIG app.log_level "debug" --revision 3 # Fails if current revision != 3 (someone else updated it) # Object Store (JetStream ObjStore — for larger binary blobs): nats object add ARTIFACTS nats object put ARTIFACTS my-binary ./binary-file nats object get ARTIFACTS my-binary -O /tmp/downloaded
5. NATS Server Configuration
Clustering, authentication, and K8s deployment
# nats-server config (nats.conf):
port: 4222
http_port: 8222 # monitoring endpoint (/healthz, /varz, /connz)
jetstream {
store_dir: /data/nats/jetstream
max_memory_store: 1Gi
max_file_store: 10Gi
}
# TLS:
tls {
cert_file: /etc/nats/tls/tls.crt
key_file: /etc/nats/tls/tls.key
ca_file: /etc/nats/tls/ca.crt
verify: true # require client certs (mTLS)
}
# Authentication (token or user/password):
authorization {
token: "my-secret-token"
# OR:
users: [{user: myapp, password: secret}]
}
# Cluster config (3-node example):
cluster {
name: my-cluster
port: 6222
routes: [
nats-route://nats-0:6222,
nats-route://nats-1:6222,
nats-route://nats-2:6222
]
}
# Docker Compose (dev):
services:
nats:
image: nats:2.10-alpine
command: ["--jetstream", "--http_port", "8222"]
ports:
- "4222:4222" # client
- "8222:8222" # monitoring
# K8s with Helm:
helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm install nats nats/nats --set config.jetstream.enabled=true --set config.cluster.enabled=true --set reloader.enabled=true
6. Observability & Debugging
Monitoring endpoints, nats CLI ops, and common issues
# Server monitoring (JSON endpoints): curl http://nats:8222/healthz # health check curl http://nats:8222/varz # server stats (connections, msgs/sec, memory) curl http://nats:8222/connz # active connections curl http://nats:8222/subz # active subscriptions curl http://nats:8222/jsz # JetStream stats (streams, consumers, bytes) # nats CLI monitoring: nats server info # server version, connections, JetStream stats nats server list # cluster members nats server report connections # connection details nats server report jetstream # JetStream cluster health # Stream health: nats stream report # all streams: messages, bytes, consumers, cluster nats stream get ORDERS 42 # get message by sequence number nats stream purge ORDERS # delete all messages (DANGEROUS) # Common issues: # - Consumer not receiving: check consumer is durable + stream subject filter matches # - Messages dropped: check stream max-msgs or max-bytes limits # - JetStream unavailable: check js.enabled in server config + sufficient resources # - Cluster split-brain: always use odd number of nodes (3 or 5)
Track NATS, Kafka, and messaging tool releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: Apache Kafka Reference | RabbitMQ Reference | Kubernetes YAML Reference
🔍 Free tool: K8s YAML Security Linter — if you deploy NATS on Kubernetes, check your manifests for 12 security misconfigurations.
Founded
2023 in London, UK
Contact
hello@releaserun.com