For a one-time read of a small NATS Key/Value key prefix or hierarchy, you usually do not need to create a watcher just to close it immediately. Use a JetStream batched Direct Get request against the KV bucket’s backing stream when you want a short-lived, consumer-free read of matching entries.
This guidance comes from a common NATS community question: how can you efficiently fetch a small hierarchy of KV keys without creating a watcher?
Use batched Direct Get when all of the following are true:
A watcher is still the right tool when you want to observe changes over time.
NATS KV watchers are useful when you want to observe changes over time. They can also provide an initial view of matching keys and then continue receiving updates.
That makes a watcher a good fit for live monitoring, but it can be awkward for short-lived lookups such as:
service.api.> onceFor those cases, creating a watcher, waiting for the initial state, and then closing it can add lifecycle complexity you may not need.
NATS KV is backed by a JetStream stream. A KV bucket named CONFIG, for example, is typically backed by a stream named:
1KV_CONFIGKV entries are stored on subjects under the bucket namespace, commonly shaped like:
1$KV.CONFIG.<key>So a KV key hierarchy such as:
1service.api.>maps to a JetStream subject filter like:
1$KV.CONFIG.service.api.>A JetStream Direct Get request can be made with a subject filter and a batch size to retrieve multiple matching messages without creating a consumer. The exact request fields and response handling depend on the client API and server version you are using; the important idea is that batched Direct Get operates directly against the stream and does not require an ephemeral consumer.
The JetStream design for this behavior, including the request fields and response framing, is described in ADR-31: JetStream Direct Get. Refer to it, and to your client documentation, for the canonical field names.
Before relying on batched Direct Get for a KV hierarchy read, confirm the following:
allow_direct and, where relevant, mirror_direct are set.Be precise about what you mean by “fetch a key hierarchy.”
A KV bucket is a convenience layer on top of JetStream. If you read the backing stream directly, you are operating below the KV API. That means you may see stream messages that represent KV revisions, deletes, or purges, depending on the bucket configuration and the request you make.
For a KV-like view of current values, you generally want the latest message per key subject, not every historical message matching the filter. If your tooling exposes a “last message per subject” helper, that is usually closer to what KV.Get semantics imply for multiple keys.
You also need to account for KV delete and purge markers. KV delete and purge operations are written to the stream with a KV-Operation header, with values such as DEL and PURGE. When you consume the backing stream directly, you see those marker messages alongside live values and must check the header before treating a message as a current key/value entry.
Some client libraries expose KV operations but do not provide a wildcard or hierarchy-oriented Get directly in the KV API. In that case, use the JetStream API beneath KV.
If you are using Synadia’s Orbit Go utilities, the JetStream extension package includes helpers such as GetBatch and GetLastMsgsFor for this style of operation:
https://github.com/synadia-io/orbit.go/tree/main/jetstreamext#getbatch-and-getlastmsgsfor
Those helpers are JetStream-level operations, not a KV-specific wildcard Get. You still need to provide the correct backing stream name and subject filter for the bucket and key hierarchy you want to read.
KV.Get, a watcher, or batched Direct Get?KV.Get when you know the exact keyChoose KV.Get when:
Choose a KV watcher when:
Choose batched Direct Get when:
For large hierarchies, long-running scans, or workflows that need continuous updates, a watcher or consumer-based approach may still be the better tradeoff.
Before using batched Direct Get for KV hierarchy reads, verify the following:
KV_<bucket>.allow_direct, and mirror_direct for mirror streams).$KV.<bucket>.<key-pattern>.KV-Operation header.For a small, one-off NATS KV hierarchy fetch, a watcher is not your only option. Because NATS KV is backed by JetStream, you can use batched Direct Get with a subject filter against the bucket’s backing stream to retrieve matching entries without creating a consumer.
The main tradeoff is that this is a lower-level JetStream operation. It can be efficient and convenient, but you are responsible for mapping KV keys to stream subjects and preserving the KV semantics you care about, especially latest-value behavior and delete markers.
Want help from the NATS experts? Meet with our architects to get help tailored to your use case and environment.



News and content from across the community