Cloudflare adds a global message queue to its Workers platform
Cloudflare has introduced a new messaging service for its Developer Platform. Cloudflare Queues, now in private beta, is a globally distributed message queuing service designed to work with Cloudflare Workers. It provides at-least-once message delivery, supports message batching, and—unlike some competing services—does not charge egress fees.
The service addresses a growing need as developers build more complex applications on Cloudflare's platform, which now includes compute via Workers and persistence via KV, Durable Objects, R2, and the upcoming D1 database. Queues adds the messaging foundation needed for larger, more reliable distributed applications.
What Queues provides
Queues act as a guaranteed delivery mechanism between services. Developers hand a message to a queue, and the queue handles the delivery work—including retries and backoffs. The at-least-once delivery guarantee means application code does not need to handle the complexity of ensuring messages are not lost.
The service also helps with load management. By batching messages, applications can decouple services that operate at different throughputs. Instead of handling a million individual messages at once, a consumer can receive them in groups, which spreads the load and makes processing more manageable.
Sending and receiving messages
Queues are integrated into the Workers runtime with APIs for both producers and consumers. A producer Worker defines a binding to a queue and can send any object to it, because messages are encoded using the standard structuredClone() algorithm. This means even JavaScript Error objects can be placed on a queue, as shown in an example where a Worker catches exceptions and sends them for processing.
export default {
async fetch(request: Request, env: Environment) {
try {
return await doRequest(request);
} catch (error) {
await env.ERROR_QUEUE.send(error);
return new Response(error.stack, { status: 500 });
}
}
}
A consumer Worker receives messages through a new queue event handler. This handler processes messages sent to the consumer, such as appending stack traces to a log file and saving them to an R2 bucket.
export default {
async queue(batch: MessageBatch<Error>, env: Environment) {
let logs = "";
for (const message of batch.messages) {
logs += message.body.stack;
}
await env.ERROR_BUCKET.put(`errors/${Date.now()}.log`, logs);
}
}
Configuration is handled through wrangler.toml when deploying with wrangler, Cloudflare's command-line tool. Developers can configure message batch size, retry counts, delivery wait time, and a dead-letter queue. Producer and consumer configurations are separate, though a single Worker can serve both roles. Full configuration options are documented in the Cloudflare Queues documentation.
name = "my-producer"
[queues]
producers = [{ queue = "errors", binding = "ERROR_QUEUE" }]
# ---
name = "my-consumer"
[queues]
consumers = [{ queue = "errors", max_batch_size = 100, max_retries = 3 }]
Use cases
Cloudflare Queues is suited for deferring tasks that must be processed eventually, decoupling services with different load profiles, and batching events for collective processing. Example applications include moving work off the critical path of a request, ensuring messages arrive at HTTP-based services, and transforming or filtering messages before fanning them out.
Routing decisions are made in JavaScript rather than through static configuration files. A developer can write logic to distribute messages to different queues based on user attributes or other criteria:
export default {
async queue(batch: MessageBatch, env: Environment) {
for (const message of batch.messages) {
const user = message.body;
if (isEUResident(user)) {
await env.EU_QUEUE.send(user);
}
if (isForgotten(user)) {
await env.DELETION_QUEUE.send(user);
}
}
}
}
Cloudflare also plans integrations with its other products, such as R2. Future capabilities could include sending R2 bucket lifecycle events to a queue or archiving queue messages to R2 for long-term storage.
Pricing
The pricing model is based on operations rather than bandwidth. Each operation—defined as any 64 KB chunk of data written, read, or deleted—costs $0.40 per million. A typical message delivery requires three operations (one write, one read, one acknowledgement), bringing the effective cost to $1.20 per million messages delivered. No bandwidth charges apply to data entering or leaving the service.
Availability
Interested developers can join the waitlist for the private beta. Cloudflare plans an open beta after the initial testing phase. Documentation with code samples is available, and the #queues-beta channel in the Cloudflare developer Discord provides updates. Enterprise customers can request a session with the product team through their account manager.



