NATS 2.11 introduced a simple but powerful JetStream feature: consumer pausing. It lets you temporarily halt message delivery to any consumer until a deadline you specify—without losing data, throwing errors, or disconnecting clients.
You need to do some maintenance. Maybe it’s a database migration, a deployment, or you just need to stop processing for a bit while you debug a production issue.
Normally you’d have to stop your application or build custom logic to handle this gracefully. With consumer pausing, you don’t have to. Messages queue up, nothing gets lost, and when you’re ready, everything picks back up.
That’s it. Works the same for both push and pull consumers.

The elegant part: your application doesn’t even know it’s happening. It just stops receiving messages. No errors, no disconnects. It keeps getting heartbeats like everything’s fine.
One thing to note: if there’s a batch already in flight (say you pulled 100 messages and you’re processing them), NATS won’t yank those away. It waits until the batch is done, then pauses before the next one.

First, create a stream to work with:
nats stream add events --subjects="events.>"Create a push consumer and subscribe:
# Create the consumernats consumer add events worker --deliver worker.inbox
# Subscribe to receive messagesnats sub worker.inboxStart publishing messages (one per second):
nats pub events.test "message {{Count}}" --count=-1 --sleep=1sPause the consumer for 10 hours:
nats consumer pause events worker 10hMessages stop flowing to your subscriber immediately. The stream still receives them—they’re just queued up waiting.
Check the consumer state:
nats consumer info events workerYou’ll see the pause deadline in the output.
Resume early when you’re ready:
nats consumer resume events workerMessages start flowing again, and you catch up on everything that was published during the pause.
Need more time? You can extend (or shorten) the pause duration at any point by calling pause again with a new deadline:
# Originally paused for 10 minutes, but need another hournats consumer pause events worker 1hThe new deadline replaces the old one—no need to resume and re-pause. This is handy when maintenance takes longer than expected or you realize you need to pause for a different amount of time.
The flow is similar for pull consumers:
# Create a pull consumernats consumer add events puller
# Start pulling messagesnats consumer next events puller --count=1000Pause with an automatic resume after 10 seconds:
nats consumer pause events puller 10sCount to ten, and messages start flowing again automatically.
You can also initialize a consumer in a paused state:
nats consumer add events worker --pause=1hOr use an absolute timestamp:
nats consumer add events worker --pause-until="2024-12-01T10:00:00Z"Here’s a simple worker that creates a consumer and processes messages:
1func main() {2 nc, _ := nats.Connect(nats.DefaultURL)3 js, _ := jetstream.New(nc)4
5 // Create stream6 js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{7 Name: "events",8 Subjects: []string{"events.>"},9 })10
11 // Create consumer12 consumer, _ := js.CreateOrUpdateConsumer(ctx, "events", jetstream.ConsumerConfig{13 Name: "worker",14 })15
16 // Start consuming in a goroutine17 go func() {18 consumer.Consume(func(msg jetstream.Msg) {19 fmt.Printf("Received: %s\n", string(msg.Data()))20 msg.Ack()21 })22 }()23
24 // Publish messages every second25 for {26 js.Publish(ctx, "events.test", []byte("hello"))27 time.Sleep(time.Second)28 }29}And a separate program to pause/resume:
1func main() {2 nc, _ := nats.Connect(nats.DefaultURL)3 js, _ := jetstream.New(nc)4
5 stream, _ := js.Stream(ctx, "events")6 consumer, _ := stream.Consumer(ctx, "worker")7
8 if os.Args[1] == "resume" {9 consumer.Resume(ctx)10 fmt.Println("Consumer resumed")11 } else {12 deadline := time.Now().Add(time.Hour)13 consumer.Pause(ctx, deadline)14 fmt.Println("Consumer paused for 1 hour")15 }16}Run the worker, then pause and resume from another terminal:
# Terminal 1go run worker.go
# Terminal 2go run pause.go pause # Messages stopgo run pause.go resume # Messages flow againConsumer pausing is simple but incredibly useful—no more custom backpressure logic just to temporarily halt processing. It’s the kind of feature that comes from years of seeing how people actually use NATS.
Pause when you need to, resume when you’re ready, and never lose a message.
We’re building the future of NATS at Synadia. Want more content like this? Subscribe to our newsletter
News and content from across the community