If you have many small values and many application replicas read all of them at startup, start by evaluating NATS Key/Value (KV), not Object Store. Object Store is usually a better fit for file-like payloads that are fetched on demand, while KV Get() is closer to a direct lookup of the latest value for a key.
This guidance comes from a real NATS community question about a bucket with many mostly-small objects and many pods fetching every object during startup.
Use KV for the common path when values are small, lookup-oriented, and read frequently by many replicas. Use Object Store for payloads that are truly object-like, large enough to benefit from chunking, or fetched selectively on demand.
For this pattern, consider:
NATS Object Store is built on JetStream. Objects are stored as chunks, and an Object Store Get() streams those chunks back to the client. To do that, the client creates an ephemeral ordered consumer for the read.
That behavior is useful for object retrieval because it gives the client ordered streaming delivery of the object chunks. However, it also means that a workload like this can create a large amount of short-lived consumer activity:
Even if most objects have only one chunk, the access pattern still behaves like many object-stream reads. The practical result can be memory and CPU pressure on the NATS servers due to rapid consumer creation and cleanup, plus the data transfer itself.
KV reads are different. A KV Get() is a direct lookup of the latest value for a key and does not create a consumer for each read in the same way. That difference is why a workload that was comfortable on KV can become expensive after moving the same shape of data to Object Store.
No. Do not plan around one-chunk objects as an optimization. Object Store is designed around streaming object chunks, and the read path uses a consumer even when the object is small enough to fit in one chunk.
If most of your data is small and you expect frequent full-bucket reads across many replicas, reconsider whether Object Store is the right primary abstraction for those values.
A common design mistake is to use the storage mechanism as the notification mechanism. These are different concerns:
Object Store is a good place to store and retrieve file-like payloads. It is not usually the best mechanism for every pod to maintain many per-object subscriptions or to re-download every object aggressively.
A more scalable design is usually:
For example, instead of creating per-object consumers, group updates by application-level dimensions such as tenant, namespace, object type, or shard. The exact subject design should match your access pattern, but the goal is to avoid 10,000 separate consumers when a smaller number of filtered consumers can express the same work.
KV is often a better fit when:
If only a small fraction of values exceed your current KV size setting, increasing the KV maximum value size may be the simpler and more appropriate option. Before doing that, review the practical limits for your deployment, including JetStream storage, account limits, client memory behavior, and the worst-case value sizes you expect.
Object Store is usually the better fit when:
Object Store is not wrong for small objects, but it can be the wrong fit for a workload that treats many small objects like a high-fanout configuration database.
Use a hybrid design:
This lets the common path stay efficient while still supporting larger data when needed.
If every pod must initialize local state from NATS, reduce the startup spike:
Get() calls per pod.These measures help, but they do not change the core tradeoff: Object Store reads are streaming object reads, not KV-style direct lookups.
For a bucket with around 10,000 mostly-small values and around 100 pods that read everything on startup, start by evaluating KV with a larger maximum value size. If the values are mostly configuration-like or lookup-oriented, KV is likely closer to the intended access pattern.
Use Object Store for the subset of data that is truly object-like or too large for the KV design. Then use a separate stream or KV-based update mechanism for notifications, with a small number of consumers per pod and subject filters where helpful.
The key design principle is to avoid coupling every stored item to its own consumer. Keep storage, lookup, and notification responsibilities separate, and choose KV or Object Store based on how the data is read most of the time.
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