Run background work with Queues
Publish messages to durable topics with @vercel/queue and process them in your functions, with retries, delays and at-least-once delivery.
Queues gives your functions durable topics: you publish a message, and every consumer group on the topic receives it at least once, with retries until it's processed or expires. Use it to move slow work out of a request, absorb spikes, or fan one event out to several pipelines.
Easel implements the same contract as Vercel Queues,
so code written with @vercel/queue
runs unchanged. There's nothing to set up: topics exist on first publish, and
your functions are authenticated automatically. Queues is in beta.
Publish and consume
Install the SDK:
Publish from any function:
Consume with a route handler wrapped in handleCallback. The message is
acknowledged when your handler returns, and retried if it throws:
Then make that route a consumer of the topic in vercel.json:
Easel invokes the route for each message. Consumer routes have no public URL: a request to one from outside returns 404, so it needs no auth of its own.
For a Pages Router or Express handler, use handleNodeCallback on a
QueueClient. To pull messages on your own schedule instead, use
PollingQueueClient#receive with a consumer group name of your choice.
How delivery works
- Every group gets every message. Each route with a trigger is its own consumer group, so two routes on one topic each get a copy. A new poll group starts with the oldest retained message.
- At least once. A message can arrive twice, for example when a handler
runs past its lease, so make handlers idempotent. Use
metadata.messageIdto deduplicate. - Retries. A delivery fails when the handler throws, crashes or times out.
The message is retried after the trigger's
retryAfterSeconds(60 seconds by default), or after what the SDK'sretrycallback returns. SetmaxDeliverieson the trigger to stop after that many attempts. - Approximate order. Messages arrive roughly in publish order, and new messages go before retries, so a failing message never blocks the rest.
- Pinned to the deployment. A deployment's consumers only receive the messages that deployment published, so a new message format never reaches old code. After you promote or roll back, the old deployment keeps draining its own messages until they're processed or expire. Deleting a deployment stops its deliveries.
Trigger options
| Option | Default | What it does |
|---|---|---|
topic | Topic to consume. * matches any characters (order-*) | |
retryAfterSeconds | 60 | Wait before retrying a failed delivery |
initialDelaySeconds | 0 | Wait after publish before the first delivery |
maxDeliveries | Unlimited | Deliveries before a message is dropped for this consumer |
maxConcurrency | Unlimited | Messages this consumer processes at once |
Publish options
A repeat publish with the same idempotency key, within the message's retention
(up to 24 hours), succeeds but is never delivered. experimental_sendBatch
publishes up to 100 messages in one request.
Monitor queues
Open your project's Observability tab and select the Queues card. You'll see messages published, received and processed over the time range, and for each topic what's waiting now and how long the oldest message has waited. A poll consumer group that hasn't received in over an hour is idle: its backlog isn't counted, so one abandoned reader doesn't make a topic look stuck. Open a topic for each consumer group's:
- Max message age: how long messages waited before a consumer got them. A climbing line means the group is falling behind.
- Retry depth: the highest delivery count any message reached. A line that keeps rising points to a message your consumer can't process.
- Waiting, in flight, dropped and processed counts, and the last error your consumer returned.
Messages stay with the deployment that published them, so an older deployment keeps delivering, and retrying, its own messages after you deploy again. The page tells you when an older production deployment still has messages waiting.
Workflows built with the Workflow SDK run on Queues, and their runs have their own page: see Workflows.
Limits
Messages can be up to 4 MiB and are kept for up to 7 days. See
Queues limits for the rest. Queues run in
iad1, the same region as your functions. Python subscribers and Vercel
Services aren't supported yet.
Pricing
Queues bill per API operation, in 4 KiB chunks of each message: publishing a
12 KiB message is three operations. A publish with an idempotency key, and a
delivery to a consumer with maxConcurrency, count double. Acknowledging a
message or changing its lease is one operation. See Pricing
for the rate and what each plan includes. The functions that process messages
bill like any other function.