Skip to content
Outer
Esc
↑↓navigate↵open⌘Jpreview
On this page

Queues guide

Background work with queues/*.ts producers and consumers — works on Outer today.

Verdict: works. Declare a queue file, send from anywhere, consume in batches. Standard Cloudflare Queues under the hood — no extra service.

1. Declare the queue

One file per queue under queues/; the path sets the name (order/notifications.ts → order-notifications):

// queues/emails.ts
import { defineQueue } from "void";

export default defineQueue<{ to: string; subject: string }>(async (batch, env) => {
  for (const msg of batch.messages) {
    await sendDigest(env, msg.body); // your function
    msg.ack();
  }
});

export const maxBatchSize = 50;
export const maxBatchTimeout = 10;
export const maxRetries = 5;
export const retryDelay = 30;

Only one consumer may read a queue. Un-acked messages ack on success and retry on throw (first call wins); over maxRetries they are permanently deleted — Void configures no dead-letter queue.

2. Produce

import { queues } from "void/queues";

await queues.emails.send({ to, subject }); // typed from defineQueue<T>

Batches cap at 100 messages / 256 KiB total, one message at 128 KiB. Delivery is at-least-once and unordered — key work by the stable msg.id and keep consumers idempotent. Retention is 4 days.

3. Deploy

Bindings come from the built dist/wrangler.json: queues is an accepted deploy key (crates/outer/src/deploy/pipeline.rs), so the queue deploys on every account — plan gating for bindings arrives with billing. Rebuild after editing queue files; consumers deploy with the app and scale with it.

Trigger local dispatch manually with the dev server’s POST /__void/queue endpoint — queued messages don’t run on their own.

Sources

Was this page helpful?