A common community question is: if you have a very large number of possible subjects, should they all belong to one JetStream stream, or should you partition them across many streams?
There is no universal limit that makes one answer correct for every deployment. The practical answer depends on memory, retention requirements, consumer behavior, and whether subscribers need historical replay or mostly live delivery.
JetStream can handle very large subject sets, but subjects are indexed in memory. As a rough sizing guideline, expect a few hundred bytes of memory overhead per subject. A deployment with around 10 million subjects can be reasonable, adding on the order of several GB of memory for subject indexes. Much larger deployments have been done, but they require careful capacity planning, testing, and operational discipline.
If your main issue is not stream storage but the number of consumers created for many small filtered subscriptions, consider whether you really need a JetStream consumer per subscriber. For workloads where most messages are consumed immediately, stream republish can move committed JetStream messages back onto ordinary NATS subjects for live subscribers, while JetStream remains the source of truth for recovery.
A stream subject list can include wildcard subjects, but once messages arrive JetStream still needs internal indexing to support subject-oriented operations. That index has memory cost.
A useful rule of thumb:
The important point is that subject count by itself is not the only question. You also need to account for:
A single stream with many subjects may be simpler than thousands of streams, but it can also concentrate operational risk and resource usage. Thousands of streams can provide partitioning boundaries, but they add management overhead. Benchmark the shape of your workload rather than relying only on stream count or subject count.
A common pattern is to partition many subjects across streams, then create consumers filtered to the small set of subjects a client needs. This can become expensive when clients frequently need different filter sets.
JetStream consumers are stateful. If your application model requires many unique filtered views, you may end up with many consumers. If filters need to change dynamically, you often have to create different consumer instances rather than treating a consumer as a lightweight mutable subscription.
One thing that can reduce the count: since NATS Server 2.10 a single consumer can specify multiple filter subjects, so a subscriber that needs a known, fixed handful of subjects can often be served by one consumer instead of one consumer per subject. The filter set is still fixed when the consumer is created, so genuinely dynamic filters still require creating a new consumer.
That does not necessarily mean one huge stream fixes the problem. Moving from many streams to one stream may reduce stream management overhead, but it does not remove the need for many filtered consumers if every subscriber still requires its own JetStream-filtered view.
Ask first: do subscribers need JetStream replay semantics for every message, or do they mostly need current live updates?
JetStream stream republish can be useful when you want to persist messages first, then fan them out to ordinary NATS subscribers.
At a high level:
Republish happens after the message has been committed to the stream. Republished messages include metadata that lets consumers identify details such as:
This pattern can drastically reduce the need for one JetStream consumer per live subscriber. Ordinary NATS subscriptions are lightweight and are a natural fit for large live fan-out.
The tradeoff is that ordinary NATS subscribers are not durable. If a subscriber disconnects, it may miss live messages. The recovery path is to consult JetStream when needed.
With a republish-based design, subscribers can use the metadata on republished messages to detect whether they missed something. When they detect a gap, they can recover from JetStream using an ephemeral consumer or a Direct Get request, depending on the exact access pattern and client support available in your environment.
This works best when:
If subscribers are frequently offline and require full durable replay, regular JetStream consumers may be the better fit despite the higher consumer count.
Another common requirement is: when a client subscribes, it should receive the latest value for a subject even if no new message is published after it connects.
That is different from ordinary live subscription. A normal NATS subscription only receives messages published after the subscription is active. A republished live stream alone does not automatically send the last stored value to a newly connected subscriber.
NATS offers more than one way to get last-value-on-connect behavior, and they trade off differently:
DeliverLastPerSubject delivery policy (deliver_last_per_subject). This kind of consumer first delivers the most recent message for each subject matching its filter, then continues with new messages. That single mechanism does combine “current value per subject” with “continue live.” The tradeoff is that it is still a consumer: if every subscriber needs its own filtered last-value view, you are back to the consumer-count consideration above.Watch delivers the current value for matching keys and then live updates, also combining initial state and live delivery in one call. KV fits well when you need only the latest value per key rather than full message history. Each watcher is still backed by a consumer, so the same per-subscriber cost applies, and KV intentionally does not retain history.Direct Get — consumer-less retrieval of a stored message, including the last message on a subject — has been available since NATS Server 2.9, and requires the stream to be created with direct access enabled (allow_direct). NATS Server 2.11 adds batched and multi-subject Direct Get, which can fetch the last message for many subjects in a single request. Client library support for the newer batched form continues to roll out, so check the client and version you are using before designing around a specific helper method.
One caveat specific to the republish design: there is no single operation that performs a Direct Get and then atomically continues a live subscription from exactly that point. Live delivery and the last-value fetch are separate, so you design around the handoff.
A common approach for the republish design is:
The exact ordering depends on your tolerance for duplicates, stale initial values, and missed updates. In distributed systems, it is often simpler to make message processing idempotent than to rely on a perfectly race-free subscribe-and-fetch transition.
DeliverLastPerSubject consumer or a KV Watch — and can absorb one consumer per subscriber.Partitioning is not only about subject count. It is also about blast radius, operational clarity, and resource isolation.
If you have around a million potential subjects, do not assume that the subject count alone requires thousands of streams. Instead:
DeliverLastPerSubject consumer or a KV Watch give last-value-on-connect from one mechanism but cost one consumer per subscriber, while republish plus Direct Get avoids per-subscriber consumers at the cost of a fetch-and-subscribe handoff to design around.The core design question is not simply how many subjects a stream can have. It is whether your stream, consumer, and subscription model matches the way clients actually consume data.
Large subject counts are feasible in JetStream, but they have memory cost and should be sized deliberately. If many filtered consumers are the bottleneck, moving all subjects into one stream may not solve the real problem. For mostly live consumption, consider stream republish to ordinary NATS subjects, with JetStream used for recovery. When clients need the latest value on connect, weigh a KV store or a DeliverLastPerSubject consumer against republish plus Direct Get. For durable per-subscriber replay, JetStream consumers remain the right abstraction, but you should budget for their operational cost.
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