How to use Cloudflare Queues in Base

A typed handoff between two workers: a producer submits and returns, a consumer chews the backlog.

Cloudflare
AhraJuly 22, 2026

How to use Cloudflare Queues in Base

A queue lets one worker hand work to another. The first worker finishes the request fast and drops a message on the queue; a second worker picks it up later and does the slow part. Sending an email, resizing an image, calling a third-party API that might be slow. The user does not wait for it, because the work moved off the request path. Base gives you a typed producer and a typed consumer, and the type of the message travels between them.

Two halves: producer and consumer

A queue has two sides, and Base models them as two things. The producer is the worker that submits messages. The consumer is the worker that processes them. They are usually separate workers, which is the whole point: the producing worker offloads work so it can return to its caller immediately, and the consuming worker chews through the backlog on its own schedule.

You can see both halves in the example pair: one project is the queue producer, the other is the queue consumer. They share the message type, which is what keeps the two sides honest about what a message contains.

Producing: submit a message

On the producing side, you ask Base for a queue bound to a named queue and you submit messages to it. The queue you get is typed to the message it carries, so the thing you submit has to match the shape that queue expects. Submitting is fire-and-set: you hand the message to the queue and return to handling your request, and Base takes care of getting it to Cloudflare's queue. You can submit a single message or a batch in one call, and you can pass send options when you need to control delivery.

The typed binding is the quiet win here. Because the queue is typed, you cannot submit a message whose shape the consumer is not prepared to handle, and the mismatch is caught at lint time rather than at runtime in production.

Consuming: process messages

On the consuming side, you write a processor and mark it as the processor for a given message type. The processor has two ways to work: handle one message at a time, or handle a batch at once. One-at-a-time is the simplest model and the right default. Batch processing is there for when handling messages together is meaningfully cheaper than handling them one by one, like writing many rows in a single database round trip.

The processor runs inside the consuming worker with full access to dependency injection, so it can reach a database, another queue, an object store, anything a normal Base handler can reach. Processing a queue message is just doing work in a worker, with the message as the input.

When to reach for a queue

Reach for a queue when work can happen after the response, when it might be slow or flaky, or when you want to smooth a spike of load into a steady stream a consumer drains at its own pace. Do not reach for one when the caller genuinely needs the result before you can answer, because a queue is asynchronous by design. The test is simple: if the user can be told "we are on it" instead of "here is the result," a queue probably fits.

The mental model to keep

A queue in Base is a typed handoff between two workers: a producer submits messages and returns immediately, a consumer processes them later, and the message type is shared so both sides agree on the shape. Submit one or many from the producer, process one or a batch in the consumer, and use it for anything that can happen after the response rather than during it.