---
title: Vercel Queues
description: The recommended scheduler on Vercel.
---

```ts server/orders.ts
import { createServer } from 'experimental-a2/server'
import { redis } from 'experimental-a2/store-redis'
import { vercelQueues } from 'experimental-a2/scheduler-vercel'
import { orders } from '@/contracts'

export const scheduler = vercelQueues()

export const ordersServer = createServer({
  contract: orders,
  store: redis({ url: process.env.REDIS_URL }),
  scheduler,
  handlers: {
    /* ... */
  },
})
```

```ts app/api/a2/scheduler/route.ts
import { ordersServer, scheduler } from '@/server'

export const POST = scheduler.handler(ordersServer)
```

```json vercel.json
{
  "functions": {
    "app/api/a2/scheduler/route.ts": {
      "experimentalTriggers": [
        {
          "type": "queue/v2beta",
          "topic": "a2"
        }
      ]
    }
  }
}
```

```package-install
npm i @vercel/queue
```

The trigger is required. It connects the route to Vercel Queues and makes the
function private, so only the queue can call it. Don't also expose the route
publicly or wrap it in your own authentication.

Messages are kept for seven days (Vercel Queues' default is 24 hours, and
seven days is its maximum), so timers can be scheduled up to seven days out. A
longer delay goes out as asked, and Vercel Queues refuses it.

A drain delivery is acknowledged once its session settles or a later watchdog
for it is stored, including when the drain fails after storing that watchdog.
A drain that fails before then stays unacknowledged, so Vercel Queues
redelivers it.

## Options

| Option | Default | |
| --- | --- | --- |
| `topic` | `'a2'` | must match the trigger's `topic`, and `[A-Za-z0-9_-]+` |
| `deploymentId` | `VERCEL_DEPLOYMENT_ID` | which deployment receives tasks; see below |
| `transport`, `clock` | the `@vercel/queue` client, the system clock | test seams for custom delivery |

An injected `transport` receives the topic, the task, and send options, and
owns its own provider configuration; `deploymentId` only configures the
built-in client.

## Deployments

`deploymentId` applies to every task: retries, timers, and scheduled clears.
Leave it out to deliver to the deployment that sent the task, pass an ID to
target one deployment, or pass `null` to let Vercel pick. Every deployment that
sends or receives must use the same setting.

- **Tasks stay with their deployment.** Promoting a new deployment doesn't move
  them, so older deployments keep receiving their own work until it's done or
  expires. Upgrading doesn't fix an older deployment's route.
- **`null` doesn't mean latest.** Vercel picks any eligible deployment, so every
  one of them must use `deploymentId: null` and handle pending tasks.
- **Changing the setting doesn't move queued tasks.** Keep the old deployments
  running until those tasks finish.
