NATS JetStream persistence layer for building distributed systems with durable messaging...
JetStream is NATS's built-in persistence engine enabling message storage and replay. Unlike Core NATS (which requires active subscriptions), JetStream captures messages and replays them to consumers as needed.
Streams store messages. Consumers read them.
This separation allows flexible deployment: one stream can have many consumers with different starting points, filters, and delivery patterns.
Use JetStream when you need:
Stick with Core NATS for:
import (
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
// Connect
nc, _ := nats.Connect(nats.DefaultURL)
js, _ := jetstream.New(nc)
// Create stream
stream, _ := js.CreateStream(ctx, jetstream.StreamConfig{
Name: "EVENTS",
Subjects: []string{"events.>"},
})
// Publish (with ack)
js.Publish(ctx, "events.user.created", []byte(`{"id": 1}`))
// Create consumer and consume
cons, _ := stream.CreateOrUpdateConsumer(ctx, jetstream.ConsumerConfig{
Durable: "my-consumer",
})
msgs, _ := cons.Fetch(10)
for msg := range msgs.Messages() {
// Process message
msg.Ack()
}
Messages published to matching subjects are stored in sequence. Streams define:
Consumers track position and provide replay capabilities:
| Policy | Use Case |
|---|---|
AckExplicit |
Default. Each message requires individual ack |
AckAll |
Ack final message = ack all prior |
AckNone |
Fire-and-forget (no redelivery) |
Ack Types:
Ack() - Success, remove from pendingNak() - Failed, redeliver immediatelyInProgress() - Extend processing deadlineTerm() - Stop redelivery (poison message)Pull (recommended for new code):
Push (legacy):
Consumers can filter stream subjects:
jetstream.ConsumerConfig{
FilterSubject: "events.us.>", // Only US events
}
| Policy | Behavior |
|---|---|
LimitsPolicy |
Keep until limits exceeded (default) |
WorkQueuePolicy |
Delete after ack (exactly-once) |
InterestPolicy |
Delete when all consumers ack |
Work queue streams require non-overlapping consumers: Multiple unfiltered consumers on a work queue stream will error. Use FilterSubject to partition.
Durable consumers persist: They don't auto-delete. Clean them up explicitly with DeleteConsumer().
JetStream publish vs Core publish: Use js.Publish() for durability guarantees. Core NATS nc.Publish() won't wait for storage confirmation.
MaxAckPending limits parallelism: Default is 1000. Increase for high-throughput consumers.
Message IDs for deduplication: Set Nats-Msg-Id header for exactly-once publishing within the deduplication window.
concepts/ - Deep dives on streams, consumers, subjects, acknowledgmentpatterns/ - Work queues, fan-out, exactly-once, event sourcingreference/ - Stream config, consumer config, CLI commandssdks/ - Go SDK patterns