A community member asked how to process a large object from a NATS Object Store over many minutes without buffering the whole object in the client, after seeing an error like:
1nats: slow consumer, messages dropped on connectionThis can happen when the application receives object chunks faster than it processes them. For example, downloading a 500 MB audio file and doing CPU-heavy signal processing inline can make the client behave like a slow consumer.
The high-level Object Store Get API is intended to download the object as quickly as possible. It has flow control, but it is not currently designed as a client-paced, long-running processing API with knobs to control the rate of object chunk delivery.
If you expect to process an object slowly over many minutes, consider dropping down to the underlying JetStream stream APIs and reading the object’s chunk messages yourself. That gives you more control over how quickly you fetch chunks and, if using a consumer, over consumer settings such as acknowledgement behavior and ack wait.
This is still JetStream. You are not dropping down to Core NATS messaging; you are bypassing the higher-level Object Store convenience API for this read path.
NATS Object Store is built on JetStream. Objects are represented as metadata plus chunk messages in an underlying JetStream stream.
The high-level Object Store Get operation is convenient when the client wants to retrieve the object normally. But if your application reads a little data and then spends a long time processing before reading more, the server and client library may continue trying to move data efficiently. If the client cannot keep up, you may see slow-consumer behavior.
This is especially relevant when:
For slow, incremental processing, use the lower-level JetStream APIs against the stream that backs the object store.
At a high level, the flow is:
One practical way to understand the exact API calls for your bucket and object is to run:
nats obj get <bucket> <name> --traceThe trace output shows the operations the CLI performs, including the metadata lookup and the chunk subject used for the object data. Use that as an inspection tool rather than hard-coding assumptions without verifying them in your environment.
A pull consumer is often the natural fit when your application wants to control pacing.
Instead of having the object data pushed to the client as fast as the Object Store Get path allows, your application explicitly fetches a small batch, processes it, acknowledges it, and then fetches the next batch. Because nothing is delivered until the application asks for it, the read rate is bounded by your processing loop rather than by the server, which is what keeps the client from becoming a slow consumer.
Conceptually:
1lookup object metadata2identify chunk subject3create pull consumer filtered to that chunk subject4loop:5 fetch one or a few chunk messages6 process chunk data7 ack messages when appropriateThis gives you control over the consumption rate. It also lets you tune consumer settings that matter for long processing, such as ack wait, depending on the behavior you want.
Tradeoffs to consider:
Another lower-level approach is to use JetStream direct get requests against the stream that backs the bucket. A direct get is a request/reply operation: the application asks for a specific message and receives it in the reply. Because there is no push subscription delivering data on its own, the client fully controls when each fetch happens, so the slow-consumer condition does not arise.
This works well when your application can address the chunk messages it needs. The object metadata records the object’s total size and chunk count, and all of an object’s chunks share a single subject and are stored in order, so the application can request them in sequence at whatever rate its processing allows.
Tradeoffs to consider:
It is still the same data stored by NATS Object Store, and it is still JetStream underneath. The difference is which API layer you use for reading:
For writes, metadata management, and ordinary reads, the Object Store API remains the simpler interface. For a special long-running processing path, using JetStream directly can be a better fit.
If your application needs 30 minutes to process a 500 MB object, avoid coupling processing directly to a high-level Get call that tries to download the object quickly.
Instead:
This approach trades convenience for control. For large objects with slow per-chunk processing, that control is often what prevents the client from becoming a slow consumer while also avoiding a full-object buffer in application memory.
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