Cloudflare.Queues reference
Consumer
Section titled “Consumer”Source:
src/Cloudflare/Queues/Consumer.ts
A Cloudflare Queue Consumer that processes messages from a Queue.
Register a Worker as a consumer of a Queue. The Worker’s queue()
handler will be invoked with batches of messages.
Cloudflare allows at most one Worker consumer per queue (HTTP-pull consumers can coexist). The reconciler enforces this: if the queue already has a Worker consumer pointing at a different logical Worker’s script, the deploy fails with a clear error rather than silently adopting it. A stranded consumer from a prior generation of the same Worker (identified by the scripts’ ownership tags) is rebuilt in place.
Consumer: Registering a Consumer
Section titled “Consumer: Registering a Consumer”Basic consumer
const queue = yield* Cloudflare.Queues.Queue("MyQueue");const worker = yield* Cloudflare.Worker("Worker", { ... });
yield* Cloudflare.Queues.Consumer("MyConsumer", { queueId: queue.queueId, scriptName: worker.workerName,});Consumer with settings
yield* Cloudflare.Queues.Consumer("MyConsumer", { queueId: queue.queueId, scriptName: worker.workerName, settings: { batchSize: 50, maxRetries: 5, maxWaitTimeMs: 10000, },});Source:
src/Cloudflare/Queues/Queue.ts
A Cloudflare Queue for reliable message passing between Workers.
Queues enable you to send and receive messages with guaranteed delivery. Create a queue as a resource, then bind it to a Worker to send messages at runtime. Register a consumer to process messages.
Queue: Creating a Queue
Section titled “Queue: Creating a Queue”Basic queue
const queue = yield* Cloudflare.Queues.Queue("MyQueue");Queue with explicit name
const queue = yield* Cloudflare.Queues.Queue("MyQueue", { name: "my-app-queue",});Queue: Binding to a Worker
Section titled “Queue: Binding to a Worker”In an Effect-style Worker, use Cloudflare.Queues.WriteQueue in
the init phase and provide Cloudflare.Queues.WriteQueueBinding in
the runtime layer. The returned WriteQueueClient exposes send
and sendBatch.
import * as Cloudflare from "alchemy/Cloudflare";import * as Effect from "effect/Effect";import { HttpServerRequest } from "effect/unstable/http/HttpServerRequest";import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
export const Queue = Cloudflare.Queues.Queue("Queue");
export default Cloudflare.Worker( "Worker", { main: import.meta.url }, Effect.gen(function* () { const queue = yield* Cloudflare.Queues.WriteQueue(Queue);
return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; if (request.url === "/queue/send" && request.method === "POST") { const text = yield* request.text; yield* queue.send({ text, sentAt: Date.now() }).pipe(Effect.orDie); return yield* HttpServerResponse.json( { sent: { text } }, { status: 202 }, ); } return HttpServerResponse.text("Not Found", { status: 404 }); }), }; }).pipe(Effect.provide(Cloudflare.Queues.WriteQueueBinding)),);Subscription
Section titled “Subscription”Source:
src/Cloudflare/Queues/Subscription.ts
A Cloudflare Queues event subscription — delivers platform events (R2 bucket events, KV namespace events, Workers Builds, Workflows, etc.) into a Queue as messages.
The source selects which product emits the events and is fixed at
creation (changing it replaces the subscription). name, events,
enabled, and the destination queueId are all mutable in place.
Cloudflare allows at most one subscription per source per account.
Subscription: Creating a Subscription
Section titled “Subscription: Creating a Subscription”R2 bucket events into a Queue
const queue = yield* Cloudflare.Queues.Queue("EventsQueue");
const subscription = yield* Cloudflare.Queues.Subscription("R2Events", { source: { type: "r2" }, events: ["bucket.created", "bucket.deleted"], queueId: queue.queueId,});KV namespace events with an explicit name
const subscription = yield* Cloudflare.Queues.Subscription("KvEvents", { name: "kv-events", source: { type: "kv" }, events: ["namespace.created"], queueId: queue.queueId,});Workers Builds events for one Worker
const subscription = yield* Cloudflare.Queues.Subscription("BuildEvents", { source: { type: "workersBuilds.worker", workerName: "my-worker" }, events: ["build.started", "build.succeeded"], queueId: queue.queueId,});Workflow lifecycle events, from a Workflow bound in this stack
Pass the Workflow binding from the host Worker’s env directly. Its
physical name remains an Output, so the subscription works on the
Workflow’s first deployment and follows later renames. Only the source
type and physical workflow name are persisted, not the binding metadata.
const worker = yield* Cloudflare.Worker("Worker", { main: "./src/worker.ts", env: { INGESTION: Cloudflare.Workflow("Ingestion", { className: "IngestionWorkflow" }) },});
const subscription = yield* Cloudflare.Queues.Subscription("WorkflowEvents", { source: worker.env.INGESTION, events: ["instance.completed", "instance.errored"], queueId: queue.queueId,});Workflow lifecycle events from a persisted resource reference
Use the logical resource ID, including any namespace. References read persisted state, so deploy the host first. Omitting the options uses the current stack and stage; the reference does not take ownership of the host.
const subscription = yield* Cloudflare.Queues.Subscription("WorkflowEvents", { source: yield* Cloudflare.Workflow.ref("Ingestion", { stack: "workflow-host", stage: "production", }), events: ["instance.completed", "instance.errored"], queueId: queue.queueId,});Workflow lifecycle events by an existing physical name
const subscription = yield* Cloudflare.Queues.Subscription("WorkflowEvents", { source: { type: "workflows.workflow", workflowName: "existing-ingestion" }, events: ["instance.completed", "instance.errored"], queueId: queue.queueId,});Subscription: Resource and Reference Sources
Section titled “Subscription: Resource and Reference Sources”Account-wide KV events from a namespace
const namespace = yield* Cloudflare.KV.Namespace("Cache");yield* Cloudflare.Queues.Subscription("NamespaceEvents", { source: namespace, events: ["namespace.created", "namespace.deleted"], queueId: queue.queueId,});KV, R2, Images, Vectorize, and Super Slurper sources are account-wide. Passing a resource retains its account and deployment dependency, but does not filter events to that resource. The subscription can miss the source’s initial creation or final deletion because it depends on that source. Use an explicit product descriptor when the subscription must exist first.
R2 bucket reference from another stack
yield* Cloudflare.Queues.Subscription("BucketEvents", { source: yield* Cloudflare.R2.Bucket.ref("Uploads", { stack: "storage", stage: "production", }), events: ["bucket.created", "bucket.deleted"], queueId: queue.queueId,});All resource forms accept yielded .ref references with optional stack
and stage selectors. The referenced resource must already be deployed in
the same Cloudflare account. Removing a subscription does not remove its
referenced resource.
Images upload events from a variant reference
yield* Cloudflare.Queues.Subscription("ImageEvents", { source: yield* Cloudflare.Images.Variant.ref("Thumbnail"), events: ["image.uploaded"], queueId: queue.queueId,});The variant selects its Images account; uploads are not filtered by variant.
Vectorize index events
yield* Cloudflare.Queues.Subscription("IndexEvents", { source: yield* Cloudflare.Vectorize.Index.ref("Search"), events: ["index.created", "index.deleted"], queueId: queue.queueId,});Super Slurper migration events
yield* Cloudflare.Queues.Subscription("MigrationEvents", { source: yield* Cloudflare.R2.SuperSlurperJob.ref("Migration"), events: ["job.completed", "job.aborted"], queueId: queue.queueId,});This selects all migration jobs in the account, not one job’s objects.
Workers AI batch events
const model = yield* Cloudflare.AI.Model("Embeddings", { modelName: "@cf/baai/bge-m3",});yield* Cloudflare.Queues.Subscription("BatchEvents", { source: model, events: ["batch.queued", "batch.succeeded", "batch.failed"], queueId: queue.queueId,});The model is a non-owning catalog handle. These events require asynchronous batch inference; ordinary synchronous inference does not emit them.
Workers Builds events from a Worker reference
yield* Cloudflare.Queues.Subscription("BuildEvents", { source: yield* Cloudflare.Worker.ref("Website"), events: ["build.started", "build.succeeded", "build.failed"], queueId: queue.queueId,});The Worker must have a Workers Builds integration to emit build events. An ordinary Alchemy Worker upload is not a Workers Builds run.
Event delivery can lag subscription creation or replacement even after the
destination Queue accepts messages. Deployment confirms configuration, not
delivery readiness; verify delivery before emitting events that must be observed.
During Vectorize subscription replacement or a destination Queue update,
Cloudflare can still route new events to the previous Queue. Replacement events
can carry the deleted subscription’s ID; updates retain the same subscription ID.
A single early event does not prove that routing has fully propagated. Keep the
previous destination available during the transition and verify the receiving
Queue, metadata.eventSubscriptionId, and the event’s resource identity.
Subscription: Pausing delivery
Section titled “Subscription: Pausing delivery”const subscription = yield* Cloudflare.Queues.Subscription("R2Events", { source: { type: "r2" }, events: ["bucket.created"], queueId: queue.queueId, enabled: false,});WriteQueue
Section titled “WriteQueue”Source:
src/Cloudflare/Queues/WriteQueue.ts
Binding service that turns a Queue resource into a typed
WriteQueueClient you can call from a Worker’s runtime Effect.
The Cloudflare Worker queue binding is producer-only — send for a
single message and sendBatch for many in one call. Messages can be
any JSON-serializable value.
WriteQueue: Sending Messages
Section titled “WriteQueue: Sending Messages”Producer route
const queue = yield* Cloudflare.Queues.WriteQueue(Queue);
return { fetch: Effect.gen(function* () { yield* queue.send({ text: "hi", sentAt: Date.now() }); return HttpServerResponse.empty({ status: 202 }); }),};Sending a batch
yield* queue.sendBatch([ { body: { event: "click", id: 1 } }, { body: { event: "click", id: 2 } }, { body: "raw text", contentType: "text" },]);Provide WriteQueueBinding (native Worker binding) or
WriteQueueHttp (scoped HTTP token) in the worker’s runtime
layer to resolve the underlying queue at request time.
WriteQueue is a single identifier that is simultaneously the binding’s
Context tag, its type, and the callable —
yield* Cloudflare.Queues.WriteQueue(queue).