Skip to main content

Overview

JetStream is NATS’ built-in persistence layer that adds streaming, message replay, and at-least-once delivery semantics to the core NATS messaging system. It transforms NATS from a pure pub/sub system into a powerful distributed streaming platform.
JetStream was introduced in NATS Server 2.2.0 and provides message persistence, replay, and guaranteed delivery without requiring external dependencies.

Why Use JetStream?

JetStream extends NATS with critical enterprise features:
  • Message Persistence: Store messages in memory or on disk for reliable delivery
  • Message Replay: Replay historical messages from any point in the stream
  • At-Least-Once Delivery: Guaranteed message delivery with acknowledgments
  • Exactly-Once Semantics: Message deduplication prevents duplicate processing
  • Stream Replication: Cluster replication for high availability (up to 3 replicas)
  • Message TTL and Limits: Automatic message expiration and stream size management

Core Concepts

Streams

Streams are message stores that capture and persist messages published to specific subjects. Each stream defines:
  • Subjects: Which message subjects to capture (supports wildcards)
  • Storage: Memory or file-based persistence
  • Limits: Maximum messages, bytes, message age
  • Retention: How long to keep messages (limits, interest, work queue)
  • Replication: Number of replicas in a cluster
type StreamConfig struct {
    Name              string
    Subjects          []string
    Retention         RetentionPolicy
    MaxConsumers      int
    MaxMsgs           int64
    MaxBytes          int64
    MaxAge            time.Duration
    MaxMsgSize        int32
    Storage           StorageType  // File or Memory
    Replicas          int          // 1, 2, or 3
    NoAck             bool
    Discard           DiscardPolicy
    DuplicateWindow   time.Duration
}

Consumers

Consumers are views into a stream that track which messages have been delivered and acknowledged. They provide:
  • Durable Consumers: Named consumers that persist delivery state
  • Ephemeral Consumers: Temporary consumers that exist only while connected
  • Delivery Modes: Push (server sends) or Pull (client requests)
  • Acknowledgment: Track message delivery and redelivery
  • Filtering: Subscribe to a subset of stream subjects
// Pull consumer for reliable processing
js.Subscribe("orders.*", func(msg *nats.Msg) {
    // Process message
    processOrder(msg.Data)
    
    // Acknowledge successful processing
    msg.Ack()
}, nats.Durable("order-processor"), nats.ManualAck())

Message Deduplication

JetStream provides exactly-once semantics through message deduplication using message IDs. Publishers can set a unique message ID, and JetStream will reject duplicates within a configurable window.
Deduplication Example
// Publisher sets message ID
js.Publish("orders.new", orderData, nats.MsgId("order-12345"))

// Stream configured with duplicate window
// Duplicate messages within window are silently ignored
stream.DuplicateWindow = 2 * time.Minute
The server tracks message IDs using SHA-256 hashing (see jetstream.go:18-19) and maintains deduplication state based on the configured window.

Persistence and Replication

Storage Types

File storage persists messages to disk for durability across server restarts.
  • Uses memory-mapped files for performance
  • Configurable sync intervals (SyncInterval, SyncAlways)
  • Stored in StoreDir (default: /tmp/jetstream or configured path)
  • Survives server restarts
Memory storage keeps messages in RAM for maximum performance.
  • Faster than file storage
  • Limited by MaxMemory configuration
  • Messages lost on server restart
  • Ideal for transient data or caching

Replication

JetStream supports stream replication in clustered deployments:
  • Replicas: 1, 2, or 3 copies across cluster nodes
  • Raft Consensus: Uses Raft protocol for consistency
  • Automatic Failover: Leader election on node failure
  • Maximum 3 Replicas: Limited to R3 for performance
Replicated Stream
nats stream add CRITICAL_ORDERS \
  --subjects "orders.critical.*" \
  --storage file \
  --replicas 3  # R3 replication for high availability

Enabling JetStream

Command Line Flag

The simplest way to enable JetStream is with the -js flag:
Enable JetStream
# Enable with default settings (dynamic limits)
nats-server -js

# Enable with custom storage directory
nats-server -js -sd /var/lib/nats/jetstream

Configuration File

For production deployments, use a configuration file:
jetstream.conf
jetstream {
    # Storage directory
    store_dir: "/var/lib/nats/jetstream"
    
    # Maximum memory storage (bytes)
    max_memory_store: 1GB
    
    # Maximum file storage (bytes)
    max_file_store: 10GB
    
    # Domain for multi-cluster setups
    domain: "production"
    
    # Sync interval for file storage
    sync_interval: 2m
    
    # Sync every write (slower but safer)
    # sync_always: true
}
If max_memory_store and max_file_store are not specified, NATS dynamically calculates limits based on available system resources (see jetstream.go:199-206).

Account Limits

JetStream supports per-account resource limits:
Account Limits
accounts {
    ORDERS: {
        jetstream: {
            max_memory: 256MB
            max_storage: 1GB
            max_streams: 10
            max_consumers: 100
        }
    }
}

Configuration Reference

Key JetStream configuration options (from jetstream.go:40-52):
max_memory
int64
Maximum size of memory storage type streams in bytes
max_storage
int64
Maximum size of file storage type streams in bytes
store_dir
string
Directory where storage files are stored
sync_interval
duration
default:"2m"
How frequently to sync to disk by calling fsync
sync_always
bool
default:"false"
Flush to disk after every write (impacts performance)
domain
string
JetStream domain for multi-cluster hierarchies
unique_tag
string
Unique tag assigned to this server instance

JetStream API

JetStream exposes a comprehensive management API over NATS subjects (see jetstream_api.go:36-200):

Stream Management

API Subjects
# Account info
$JS.API.INFO

# Stream operations
$JS.API.STREAM.CREATE.<stream>
$JS.API.STREAM.UPDATE.<stream>
$JS.API.STREAM.DELETE.<stream>
$JS.API.STREAM.INFO.<stream>
$JS.API.STREAM.LIST
$JS.API.STREAM.PURGE.<stream>

# Message operations
$JS.API.STREAM.MSG.GET.<stream>
$JS.API.STREAM.MSG.DELETE.<stream>
$JS.API.DIRECT.GET.<stream>  # Direct message access

Consumer Management

Consumer API
# Consumer operations
$JS.API.CONSUMER.CREATE.<stream>
$JS.API.CONSUMER.CREATE.<stream>.<consumer>.<filter>
$JS.API.CONSUMER.DELETE.<stream>.<consumer>
$JS.API.CONSUMER.INFO.<stream>.<consumer>
$JS.API.CONSUMER.LIST.<stream>
$JS.API.CONSUMER.MSG.NEXT.<stream>.<consumer>
Use the nats CLI or client SDKs instead of calling API subjects directly.

Monitoring

Monitor JetStream statistics via the /jsz endpoint:
JetStream Monitoring
curl http://localhost:8222/jsz

# With account details
curl http://localhost:8222/jsz?accounts=true

# With stream and consumer details
curl http://localhost:8222/jsz?accounts=true&streams=true&consumers=true
See the Monitoring page for more details.

Statistics

JetStream tracks detailed usage statistics (jetstream.go:54-63):
  • Memory Usage: Current memory storage used
  • Store Usage: Current file storage used
  • Reserved Resources: Pre-allocated account limits
  • API Statistics: Total requests, errors, inflight
  • Accounts: Number of JetStream-enabled accounts
  • HA Assets: Replicated streams and consumers

Best Practices

Use File Storage

Use file storage for streams that must survive restarts. Reserve memory storage for caching and transient data.

Configure Limits

Always set appropriate limits (max_msgs, max_bytes, max_age) to prevent unbounded growth.

Enable Replication

Use R3 replication for critical streams in production clusters.

Message Deduplication

Use message IDs for exactly-once semantics with configurable duplicate windows.

Next Steps

Configuration

Configure JetStream for your deployment

Monitoring

Monitor JetStream metrics and health

Architecture

Understand NATS Server architecture

MQTT

MQTT implementation uses JetStream

Build docs developers (and LLMs) love