Loading...
Loading...
Vercel Queues guidance — durable topics with at-least-once delivery, independent consumer groups, retries, delays, and idempotency keys via @vercel/queue (JS) or vercel-queue (Python). Use when deferring background work, buffering traffic, fanning out events, or choosing between Queues and Workflows.
npx skill4agent add vercel/vercel-plugin queues| Need | Use | Why |
|---|---|---|
| Fire-and-forget background job, fan-out, buffering | Queues | Direct publish/consume, independent consumer groups |
| Multi-step logic with sleep, hooks, or human approval | Workflows ( | Durable steps and replay built on top of Queues |
| Scheduled invocation on a cron | Cron Jobs ( | Time-based trigger, not message-based |
npm install @vercel/queue// app/api/orders/route.ts
import { send } from '@vercel/queue';
export async function POST(request: Request) {
const body = await request.json();
const { messageId } = await send('orders', { orderId: body.orderId, action: 'process' });
return Response.json({ messageId });
}// app/api/queues/process-order/route.ts
import { handleCallback } from '@vercel/queue';
export const POST = handleCallback(async (message, metadata) => {
await processOrder(message);
console.log('processed', metadata.messageId, 'delivery', metadata.deliveryCount);
});vercel.jsonvercel.ts{
"functions": {
"app/api/queues/process-order/route.ts": {
"experimentalTriggers": [{ "type": "queue/v2beta", "topic": "orders" }]
}
}
}vercel linkvercel env pullawait send('orders', payload, {
region: 'sfo1', // target a specific region
retentionSeconds: 3600, // message TTL; min 60, max 604800 (7 days); default 24 hours
delaySeconds: 60, // delay first delivery; max 7 days, capped at the TTL
idempotencyKey: 'order-123', // duplicates within the retention window are dropped
headers: { 'x-trace-id': 'abc-123' },
});QueueClient// lib/queue.ts
import { QueueClient } from '@vercel/queue';
const queue = new QueueClient({ region: 'sfo1' });
export const { send, handleCallback } = queue;handleCallback(handler, options)| Option | Default | Notes |
|---|---|---|
| 300 | How long a message stays in flight; the SDK re-extends the lease while the handler runs |
| built-in backoff | |
export const POST = handleCallback(processOrder, {
retry: (error, metadata) => {
if (metadata.deliveryCount > 5) return { acknowledge: true }; // stop retrying
return { afterSeconds: Math.min(300, 2 ** metadata.deliveryCount * 5) };
},
});metadatamessageIddeliveryCountcreatedAtexpiresAttopicNameconsumerGroupregionqueue.handleNodeCallback(async (message, metadata) => ...)QueueClient(req, res)vercel-queuevercel.queues.triggersnitro.config.tsvercel:queuesend@vercel/queueBufferTransportStreamTransportQueueClient@vercel/queueUnauthorizedErrorBadRequestErrorDuplicateMessageErrorMessageNotFoundErrorQueueEmptyErrorhandleCallbackexperimentalTriggersvercel.jsonvercel.tsmetadata.messageIdidempotencyKeyretryvercel linkvercel env pullsend()UnauthorizedError