An inactive consumer is a JetStream consumer that has made no delivery progress — zero new messages delivered — across the observed time range. Its delivered_stream_seq remains unchanged throughout the evaluation period. The consumer exists in the server’s metadata, holds a Raft group (if replicated), but no application is actively pulling or receiving messages from it.
Every JetStream consumer carries operational cost. A durable consumer maintains its delivered sequence, ack state, and configuration in the server’s metadata. For replicated consumers (R3), each one runs its own Raft group with leader elections, heartbeats, and state replication across three servers. A handful of forgotten consumers are harmless. Dozens or hundreds of them create real overhead — more Raft groups mean more CPU spent on consensus, more memory for tracking state, and larger meta snapshots that slow down server restarts.
The more insidious problem is retention interaction. Streams configured with an interest-based retention policy only delete messages once all consumers have acknowledged them. An inactive consumer that never acknowledges anything effectively pins the stream’s storage at its high-water mark. The stream keeps growing, retention never fires, and the operator sees disk usage climbing without an obvious cause. This is one of the most common “mystery disk growth” scenarios in JetStream deployments.
Inactive consumers also create operational noise. When operators run nats consumer report to understand their system, pages of inactive consumers obscure the active ones that actually matter. During incidents, this clutter slows diagnosis. During capacity planning, it inflates asset counts and makes the system look busier than it is.
Application was retired without cleaning up its consumer. A service that consumed from a stream was decommissioned, but nobody deleted the durable consumer it created. This is the most common cause by far, especially in organizations without a formal consumer lifecycle process.
Consumer was created for testing or debugging. An operator created a consumer to inspect stream contents during an investigation, then forgot to delete it afterward. Test consumers with names like test-1 or debug-consumer are a strong signal.
Push consumer with no active subscriber. A push consumer has a deliver subject configured, but no application is subscribed to that subject. The consumer exists and has messages pending, but nothing is receiving them. See also: OPT_SYS_004 (Unbound Push Consumer).
Consumer filter subject no longer matches any published subjects. The consumer’s filter subject was valid when created, but publishers have since changed their subject hierarchy. The consumer is technically active but will never receive new messages because nothing publishes to subjects it cares about.
Deployment failure left the consumer orphaned. A new version of a service was deployed with a different consumer name (or on a different stream), but the old consumer was never cleaned up. The old consumer sits idle while the new one handles the workload.
Start with a report across all consumers on a stream:
nats consumer report ORDERSThis shows each consumer’s delivered count, ack pending, unprocessed messages, and last activity. Consumers with zero unprocessed messages and no recent last activity timestamp are likely inactive.
For a broader view across all streams:
nats stream report --consumersGet detailed state for a suspect consumer:
nats consumer info ORDERS my-consumerKey fields to check:
For push consumers, verify whether anyone is listening on the deliver subject:
nats server report connections --subscriptions --filter-subject "deliver.ORDERS.my-consumer"If no connections are subscribed to the deliver subject, the push consumer is unbound and effectively inactive.
nats stream info ORDERSIf the stream uses interest-based retention, an inactive consumer blocks message deletion. Check whether the stream’s first sequence is advancing or stuck.
If you’ve confirmed a consumer is no longer needed, delete it:
nats consumer delete ORDERS my-consumerFor bulk cleanup, list and filter:
nats consumer ls ORDERS -j | jq -r '.[] | select(.num_pending == 0) | .name'Review the output and delete consumers that are confirmed inactive. Don’t blindly delete — a consumer with zero pending may simply be caught up and actively waiting for new messages.
Ephemeral consumers support an inactive_threshold that automatically deletes the consumer after a period of no client activity:
1// Go - nats.go2js, _ := nc.JetStream()3
4_, err := js.Subscribe("orders.>", handler,5 nats.InactiveThreshold(10*time.Minute),6 nats.ManualAck(),7)1# Python - nats.py2from nats.js.api import ConsumerConfig3
4await js.subscribe(5 "orders.>",6 cb=handler,7 config=ConsumerConfig(inactive_threshold=600), # seconds8)This prevents future ephemeral consumers from becoming permanently inactive. It doesn’t help with existing durable consumers, which must be explicitly deleted.
Name consumers with ownership metadata. Use a naming convention that encodes the owning service and environment: orderprocessor-prod-v2 instead of consumer1. When a consumer’s owning service is decommissioned, you know which consumers to clean up.
Audit consumers as part of service decommissioning. Add a step to your deployment runbook: when retiring a service, list its consumers and delete them. This is cheaper than discovering them months later during a storage investigation.
Use Synadia Insights for continuous monitoring. Insights evaluates consumer activity across your entire deployment automatically. Instead of running manual nats consumer report commands, inactive consumers surface as findings without any operator intervention — across every stream, every account, every collection cycle.
Synadia Insights flags consumers whose delivered_stream_seq hasn’t changed across the selected time range. The exact duration depends on your observation window — typically hours to days. A consumer that hasn’t delivered a single message in 24 hours on a stream that’s actively receiving publishes is almost certainly inactive. A consumer on a stream that only receives messages weekly may be fine. Context matters.
Yes. Interest-based retention deletes messages only after all defined consumers have acknowledged them. An inactive consumer never acknowledges anything, so messages are never deleted. This is the most operationally dangerous side effect of inactive consumers — it can fill disks silently. If you use interest-based retention, auditing consumer activity is not optional.
An inactive consumer has stopped making delivery progress entirely — its delivered sequence is frozen. A drained consumer (OPT_IDLE_004) is caught up: it has processed all available messages and has zero pending, but the stream itself is also inactive. A drained consumer was doing its job; there’s just nothing left to do. An inactive consumer may have stopped for a reason that needs investigation.
For ephemeral consumers, yes — use inactive_threshold to let the server handle cleanup automatically. For durable consumers, be more careful. Durable consumers track delivery state that an application may rely on when it restarts. Deleting a durable consumer means the application will need to re-create it, potentially reprocessing messages from the stream’s first available sequence. Verify with the owning team before deleting durable consumers.
Yes. Every consumer, active or not, uses memory for its state tracking. Replicated consumers (R3) maintain a Raft group with ongoing heartbeat traffic and leader election participation. The per-consumer overhead is small individually, but it compounds. Clusters with thousands of inactive consumers can see measurable impact on meta snapshot times and Raft consensus performance.
With 100+ always-on audit Checks from the NATS experts, Insights helps you find and fix problems before they become costly incidents.
No alert rules to write. No dashboards to maintain.
News and content from across the community