daemons

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vercel Daemons

Vercel Daemons

You are an expert in Vercel Daemons, the long-running background processes that run from a container image in the same project as an app.
Daemons are in Public Beta on all plans. Say so when you recommend them.
你是 Vercel Daemons 专家。Vercel Daemons 是与应用在同一项目中、从容器镜像运行的长时间后台进程。
Daemons 已在所有套餐上进入 Public Beta。推荐它们时请说明这一点。

What It Is

什么是它

A daemon is a named resource in a project that runs a fixed number of identical instances of one container image in each region you list. Vercel builds the image from the daemon's
Dockerfile
or
Containerfile
, rolls it out when the deployment becomes the production deployment, restarts instances that exit or crash, and forwards
stdout
/
stderr
to the project's Logs. Daemons run on Fluid compute.
Daemons cannot receive inbound traffic. They pull work from a queue, a workflow engine, or an external API.
daemon 是一种项目内的命名资源,它会在你列出的每个 region 中运行同一个容器镜像的固定数量的相同实例。Vercel 使用 daemon 的
Dockerfile
或
Containerfile
构建镜像;当部署成为生产部署时,Vercel 会滚动发布该镜像;退出的实例或崩溃的实例会被重启;
stdout
/
stderr
则会转发到项目的 Logs。Daemons 运行在 Fluid Compute 上。
Daemons 无法接收入站流量。它们从 queue、workflow engine 或 external API 拉取工作。

When to Use Daemons

何时使用 Daemons

Use a daemon when the process owns a continuous loop that retrieves work.
NeedUseWhy
Always-on queue consumer (Vercel Queues poll mode, SQS, Kafka, Redis), Celery/Sidekiq/BullMQ worker, workflow-engine worker, self-hosted CI runnerDaemonsLong-running loop, fixed instances per region, no request needed
HTTP APIs, webhooks, streaming, WebSocketsVercel Functions (
⤳ skill: vercel-functions
)
Daemons can't receive traffic
Fire-and-forget background job, fan-out, buffering with Vercel invoking your handlerVercel Queues push mode (
⤳ skill: queues
)
Serverless, scales automatically, works in previews
Durable multi-step logic with sleep, hooks, or approvalsVercel Workflows (
⤳ skill: workflow
)
Durable steps and replay
Run code on a scheduleCron Jobs (
⤳ skill: vercel-functions
)
Time-based trigger
Run untrusted or AI-generated code in isolationVercel Sandbox (
⤳ skill: vercel-sandbox
)
Ephemeral microVMs
Multiple frontends and backends in one projectVercel Services (
⤳ skill: vercel-services
)
Daemons sit next to services; they are not services
If the user's work is request-driven, prefer Functions or Queues push mode. Reach for a daemon only when something must stay running.
当进程拥有一个用于获取工作的持续循环时,使用 daemon。
需求使用原因
始终运行的 queue 消费者(Vercel Queues poll mode、SQS、Kafka、Redis)、Celery/Sidekiq/BullMQ worker、workflow-engine worker、自托管 CI runnerDaemons长时间运行的循环、每个 region 固定数量的实例、无需发起请求
HTTP API、Webhook、流式传输、WebSocketsVercel Functions(
⤳ skill: vercel-functions
)
Daemons 无法接收流量
Fire-and-forget 后台任务、fan-out、由 Vercel 调用 handler 进行缓冲Vercel Queues push mode(
⤳ skill: queues
)
Serverless、自动扩缩容、可在 preview 中运行
包含 sleep、hook 或审批的 Durable 多步骤逻辑Vercel Workflows(
⤳ skill: workflow
)
Durable 步骤与重放
按计划运行代码Cron Jobs(
⤳ skill: vercel-functions
)
基于时间的触发器
在隔离环境中运行不受信任或 AI 生成的代码Vercel Sandbox(
⤳ skill: vercel-sandbox
)
临时 microVM
在一个项目中包含多个前端和后端Vercel Services(
⤳ skill: vercel-services
)
Daemons 与 Services 并列运行;它们不是 Services
如果用户的工作由请求驱动,请优先使用 Functions 或 Queues push mode。只有当某项任务必须持续运行时,才使用 daemon。

Quick Start

快速开始

Add a
Dockerfile
in the worker's source directory:
docker
undefined
在工作进程的源代码目录中添加
Dockerfile
:
docker
undefined

worker/Dockerfile

worker/Dockerfile

FROM node:24-slim WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --omit=dev COPY . . CMD ["node", "worker.js"]

Declare the daemon under the top-level `daemons` key:

```json filename="vercel.json"
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 2 }
    }
  }
}
The same configuration works in
vercel.toml
as a
[daemons.worker]
table. Deploy to production. Vercel builds the image, pushes it to Vercel Container Registry as
daemon.worker
, and starts two instances in
iad1
.
Daemons are always declared at the top level, never inside
services
. They run alongside an existing app (Next.js, Services, or anything else) without changing how Vercel builds it.
FROM node:24-slim WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --omit=dev COPY . . CMD ["node", "worker.js"]

在顶层 `daemons` 键下声明 daemon:

```json filename="vercel.json"
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 2 }
    }
  }
}
同一配置也可在
vercel.toml
中写作
[daemons.worker]
表。部署到生产环境后,Vercel 会构建镜像,将其以
daemon.worker
的名称推送到 Vercel Container Registry,并在
iad1
启动两个实例。
Daemons 始终在顶层声明,绝不能放在
services
内。它们可以与现有应用(Next.js、Services 或其他任何内容)并行运行,而无需改变 Vercel 构建该应用的方式。

Configuration Reference

配置参考

FieldTypeRequiredNotes
root
string
YesSource directory, relative to
vercel.json
. Must stay inside the project. Files under it are not published as static assets
entrypoint
string
YesPath to the
Dockerfile
or
Containerfile
, relative to
root
. Its directory is the build context
instances
Record<region, number>
YesInstances per region ID, each
0
–
100
. Vercel runs only in the listed regions
command
string[]
NoReplaces the image's
ENTRYPOINT
and
CMD
. Not run through a shell
resources
{ requests: { memory } }
No
1Gi
(1 vCPU),
2Gi
(1 vCPU, default),
4Gi
(2 vCPU),
8Gi
(4 vCPU)
  • instances
    vs
    replicas
    : the published
    vercel.json
    schema and the Build Output API use
    instances
    .
    replicas
    is a deprecated alias that is ignored when
    instances
    is set. If the project already uses
    replicas
    , leave it working, but write
    instances
    in new configuration.
  • Names: lowercase letters only, joined by
    _
    ,
    __
    , or one or more
    -
    (
    worker
    ,
    email_sender
    ,
    celery-beat
    ; not
    Worker
    ,
    worker1
    ,
    _worker
    ), 64 characters max. Two names that collapse to the same image repository once repeated hyphens are merged, such as
    a-b
    and
    a--b
    , fail the build. A daemon and a service may share a name.
  • Rejected fields: service fields such as
    framework
    ,
    runtime
    ,
    buildCommand
    , and
    bindings
    fail validation on a daemon.
  • Build: images are built for Linux
    amd64
    . Deployment environment variables are passed to the image build as build arguments.
  • Shell features:
    command
    is exec-form. Use
    ["sh", "-c", "exec node worker.js --id $WORKER_ID"]
    for variable expansion.
  • No
    CMD
    : the build fails if the image has neither
    ENTRYPOINT
    nor
    CMD
    and
    command
    is not set.
json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "celery": {
      "root": "backend/",
      "entrypoint": "Dockerfile",
      "command": ["celery", "-A", "app", "worker", "--loglevel=info"],
      "instances": { "iad1": 2, "cdg1": 1 },
      "resources": { "requests": { "memory": "4Gi" } }
    }
  }
}
字段类型必填说明
root
string
是相对于
vercel.json
的源代码目录,必须位于项目内部。其下的文件不会作为静态资源发布
entrypoint
string
是相对于
root
的
Dockerfile
或
Containerfile
路径。其所在目录是 build context
instances
Record<region, number>
是每个 region ID 的实例数,每项为
0
–
100
。Vercel 仅在列出的 region 中运行
command
string[]
否替换镜像的
ENTRYPOINT
和
CMD
。不会通过 shell 运行
resources
{ requests: { memory } }
否
1Gi
(1 vCPU)、
2Gi
(1 vCPU,默认)、
4Gi
(2 vCPU)、
8Gi
(4 vCPU)
  • instances
    与
    replicas
    :已发布的
    vercel.json
    schema 和 Build Output API 使用
    instances
    。
    replicas
    是已弃用的别名,当设置了
    instances
    时会被忽略。如果项目已经使用
    replicas
    ,可以保持其继续工作,但新配置应使用
    instances
    。
  • 名称:只能使用小写字母,并以
    _
    、
    __
    或一个或多个
    -
    连接(
    worker
    、
    email_sender
    、
    celery-beat
    ;不能使用
    Worker
    、
    worker1
    、
    _worker
    ),最长 64 个字符。如果两个名称在合并重复连字符后归并为同一个镜像仓库,例如
    a-b
    和
    a--b
    ,则构建失败。daemon 与 service 可以使用相同名称。
  • 不允许的字段:daemon 中使用
    framework
    、
    runtime
    、
    buildCommand
    和
    bindings
    等 service 字段会触发验证失败。
  • 构建:镜像面向 Linux
    amd64
    构建。部署环境变量会作为 build arguments 传入镜像构建过程。
  • Shell 功能:
    command
    采用 exec 形式。需要展开变量时,请使用
    ["sh", "-c", "exec node worker.js --id $WORKER_ID"]
    。
  • 没有
    CMD
    :如果镜像既没有
    ENTRYPOINT
    也没有
    CMD
    ,并且未设置
    command
    ,则构建失败。
json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "celery": {
      "root": "backend/",
      "entrypoint": "Dockerfile",
      "command": ["celery", "-A", "app", "worker", "--loglevel=info"],
      "instances": { "iad1": 2, "cdg1": 1 },
      "resources": { "requests": { "memory": "4Gi" } }
    }
  }
}

Lifecycle and Scaling

生命周期与扩缩容

  • Production only during the beta. Daemons run only for the production deployment. Preview deployments do not start daemons; test changes by running the image locally.
  • Rollout: when a deployment becomes production (deploy, promote, Instant Rollback, or a completed rolling release), Vercel starts the new instances and sends
    SIGTERM
    to the previous deployment's instances. For a short time both versions run at once, so both must be able to consume the same queue and tolerate the same database schema.
  • Image, command, and environment variables belong to the deployment. Change them with a new production deployment.
  • Scaling with
    vercel.json
    : change
    instances
    and deploy to production. The map replaces the previous one; regions removed from it stop.
  • Scaling overrides: in the project dashboard, Daemons → select the daemon → Set Scaling Overrides. Overrides persist across deployments and win over
    instances
    until cleared with Clear scaling overrides. If a
    vercel.json
    change to
    instances
    seems ignored, check for an override first. There is no autoscaling, and scaling from the CLI or API is not available yet.
  • Stop without deleting: set every region to
    0
    or
    instances
    to
    {}
    , or set a
    0
    override from the dashboard.
  • Delete: remove the daemon from
    daemons
    and deploy to production.
  • Paused projects stop all daemon instances; they start again when the project resumes.
  • Beta 期间仅在生产环境运行。 Daemons 仅为生产部署运行。Preview 部署不会启动 daemons;请通过在本地运行镜像来测试更改。
  • 滚动发布:当部署成为生产部署时(deploy、promote、Instant Rollback 或完成滚动发布),Vercel 会启动新实例,并向旧部署的实例发送
    SIGTERM
    。短时间内两个版本会同时运行,因此二者都必须能够消费同一个 queue,并兼容同一个 database schema。
  • 镜像、命令和环境变量属于部署的一部分。通过新的生产部署进行更改。
  • 使用
    vercel.json
    扩缩容
    :修改
    instances
    并部署到生产环境。该 map 会替换之前的 map;从中移除的 region 将停止运行。
  • 扩缩容覆盖:在项目控制台中,进入 Daemons → 选择 daemon → 设置扩缩容覆盖(Set Scaling Overrides)。覆盖配置会跨部署持久保留,并优先于
    instances
    ,直到通过**清除扩缩容覆盖(Clear scaling overrides)**将其清除。如果
    vercel.json
    中对
    instances
    的更改似乎未生效,请先检查是否存在覆盖配置。当前不支持自动扩缩容,也无法通过 CLI 或 API 扩缩容。
  • 停止但不删除:将每个 region 的实例数设置为
    0
    ,或将
    instances
    设置为
    {}
    ,也可以在控制台中设置
    0
    覆盖值。
  • 删除:从
    daemons
    中移除 daemon,并部署到生产环境。
  • 已暂停的项目会停止所有 daemon 实例;项目恢复后,这些实例会重新启动。

Graceful Shutdown

优雅停机

Vercel sends
SIGTERM
on rollout, scale-down, removal, and manual restart, then waits 10 seconds by default before terminating the process. Stop taking new work immediately and finish the job in progress. Instances can stop at any time, so jobs must be idempotent and safe to retry; acknowledge a queue message only after processing it.
ts
// worker/worker.ts
const shutdown = new AbortController();
process.on('SIGTERM', () => shutdown.abort());

async function main(): Promise<void> {
  while (!shutdown.signal.aborted) {
    await processNextJob(shutdown.signal); // bounded poll; back off when there is no work
  }
  process.exit(0);
}

void main();
python
undefined
在滚动发布、缩容、移除和手动重启时,Vercel 会发送
SIGTERM
,随后默认等待 10 秒再终止进程。应立即停止领取新工作,并完成正在处理的任务。实例可能随时停止,因此任务必须具备幂等性,并且能够安全重试;只有在处理完成后才能确认 queue message。
ts
// worker/worker.ts
const shutdown = new AbortController();
process.on('SIGTERM', () => shutdown.abort());

async function main(): Promise<void> {
  while (!shutdown.signal.aborted) {
    await processNextJob(shutdown.signal); // bounded poll; back off when there is no work
  }
  process.exit(0);
}

void main();
python
undefined

worker/worker.py

worker/worker.py

import signal from threading import Event
shutdown = Event() signal.signal(signal.SIGTERM, lambda signum, frame: shutdown.set())
while not shutdown.is_set(): process_next_job(shutdown) # bounded poll, finish the current job before returning
undefined
import signal from threading import Event
shutdown = Event() signal.signal(signal.SIGTERM, lambda signum, frame: shutdown.set())
while not shutdown.is_set(): process_next_job(shutdown) # bounded poll, finish the current job before returning
undefined

Consuming Vercel Queues From a Daemon

从 Daemon 消费 Vercel Queues

A daemon is the long-running consumer for Vercel Queues poll mode. Use
PollingQueueClient
from
@vercel/queue
with an explicit region, because messages can only be received from the region they were sent to:
ts
// worker/worker.ts
import { PollingQueueClient } from '@vercel/queue';

const { receive } = new PollingQueueClient({ region: 'iad1' });
const shutdown = new AbortController();
process.on('SIGTERM', () => shutdown.abort());

while (!shutdown.signal.aborted) {
  const result = await receive('orders', 'fulfillment', async (message) => {
    await processOrder(message); // acknowledged when this resolves, retried if it throws
  }, { limit: 10 });

  if (!result.ok && result.reason === 'empty') {
    await new Promise((r) => setTimeout(r, 1000));
  }
}
Run the daemon in the same region the producer sends to. Topics are partitioned by deployment ID by default; read the poll-mode versioning section before relying on cross-deployment consumption. For the producer side and push-mode consumers, load
⤳ skill: queues
.
daemon 是 Vercel Queues poll mode 的长时间运行消费者。请使用
@vercel/queue
中的
PollingQueueClient
并显式指定 region,因为消息只能从其被发送到的 region 中接收:
ts
// worker/worker.ts
import { PollingQueueClient } from '@vercel/queue';

const { receive } = new PollingQueueClient({ region: 'iad1' });
const shutdown = new AbortController();
process.on('SIGTERM', () => shutdown.abort());

while (!shutdown.signal.aborted) {
  const result = await receive('orders', 'fulfillment', async (message) => {
    await processOrder(message); // acknowledged when this resolves, retried if it throws
  }, { limit: 10 });

  if (!result.ok && result.reason === 'empty') {
    await new Promise((r) => setTimeout(r, 1000));
  }
}
请将 daemon 部署在与生产者发送到同一 region。Topics 默认按 deployment ID 分区;在依赖跨 deployment 消费之前,请先阅读 poll-mode 的版本控制章节。如需了解生产者端和 push-mode 消费者,请加载
⤳ skill: queues
。

Environment Variables and OIDC

环境变量与 OIDC

  • Each instance receives the deployment's environment variables.
  • Each instance receives an OIDC token written to a file whose path is in
    VERCEL_OIDC_TOKEN_FILE
    , refreshed periodically. Read it with
    @vercel/oidc
    4.0.0 or later (Node.js) or
    vercel-oidc
    0.10.0 or later (Python). Older SDK versions that only read
    VERCEL_OIDC_TOKEN
    will not find it.
  • 每个实例都会收到该 deployment 的环境变量。
  • 每个实例都会收到一个写入文件的 OIDC token,文件路径由
    VERCEL_OIDC_TOKEN_FILE
    指定,并且会定期刷新。请使用
    @vercel/oidc
    4.0.0 或更高版本(Node.js),或
    vercel-oidc
    0.10.0 或更高版本(Python)读取该文件。只读取
    VERCEL_OIDC_TOKEN
    的旧版 SDK 将找不到该文件。

Local Development

本地开发

vercel dev
does not run daemons; it prints a warning and starts the rest of the project. Run the daemon with Docker instead:
bash
vercel env pull                       # writes .env.local
docker build -t worker worker/
docker run --env-file .env.local worker
vercel dev
不会运行 daemons;它会打印一条警告并启动项目的其余部分。请改用 Docker 运行 daemon:
bash
vercel env pull                       # writes .env.local
docker build -t worker worker/
docker run --env-file .env.local worker

Logs and Observability

日志与可观测性

Daemon output appears in the project's Logs with source
daemon
and the daemon's name, so you can filter to one daemon. The project dashboard's Daemons tab shows each daemon's instances, status, and logs.
daemon 输出会出现在项目 Logs 中,source 为
daemon
,并带有 daemon 的名称,因此可以筛选到特定 daemon。项目控制台的 Daemons 选项卡会显示每个 daemon 的实例、状态和日志。

Build Output API

Build Output API

With
vercel build
or a custom builder,
.vercel/output/config.json
lists daemons as
"daemons": { "worker": {} }
(the complete set; omitted daemons are stopped), and each has
.vercel/output/daemons/<name>/.vc-config.json
with
runtime: "container"
, an
image
already in Vercel Container Registry,
instances
, and optional
command
and
resources
.
vercel build
builds and pushes the images and writes these files for you.
使用
vercel build
或自定义 builder 时,
.vercel/output/config.json
会将 daemons 列为
"daemons": { "worker": {} }
(这是完整集合;未列出的 daemons 会停止运行),每个 daemon 都有对应的
.vercel/output/daemons/<name>/.vc-config.json
,其中包含
runtime: "container"
、已位于 Vercel Container Registry 的
image
、
instances
,以及可选的
command
和
resources
。
vercel build
会为你构建并推送镜像,并写入这些文件。

Limits

限制

LimitValue
Instances per region100 per daemon
Memory per instance1, 2 (default), 4, or 8 GiB
Shutdown grace period10 seconds after
SIGTERM
by default
CPU architectureLinux
amd64
Default per-team quotas apply during the beta: Hobby is limited to 1–2 GiB instances and a monthly vCPU-hour allowance (instances stop when it runs out), Pro allows all sizes up to a concurrent vCPU and memory cap, and Enterprise is custom. Check Daemons limits for the current numbers before sizing a deployment.
Not supported during the beta: preview deployments, inbound HTTP or TCP traffic, autoscaling, persistent local storage (use Vercel Blob or a Marketplace database), running in
vercel dev
, being the target of a service binding or rewrite, builds without a
Dockerfile
/
Containerfile
, and projects whose root directory is a subfolder such as
apps/web
.
限制值
每个 region 的实例数每个 daemon 100 个
每个实例的内存1、2(默认)、4 或 8 GiB
停机宽限期收到
SIGTERM
后默认 10 秒
CPU 架构Linux
amd64
Beta 期间会应用默认的团队级配额:Hobby 仅可使用 1–2 GiB 实例,并受每月 vCPU-hour 配额限制(配额用尽后实例会停止);Pro 允许使用所有规格,但受并发 vCPU 和内存上限约束;Enterprise 可定制。在确定部署规格之前,请查看 Daemons limits 以了解当前数值。
Beta 期间尚不支持:preview 部署、入站 HTTP 或 TCP 流量、自动扩缩容、持久化本地存储(请使用 Vercel Blob 或 Marketplace database)、在
vercel dev
中运行、作为 service binding 或 rewrite 的目标、缺少
Dockerfile
/
Containerfile
的构建,以及根目录为
apps/web
等子文件夹的项目。

Common Pitfalls

常见问题

  1. Expecting traffic: a daemon that listens on a port receives nothing. Serve requests with Functions or Services, and have the daemon pull work.
  2. Testing on a preview: daemons never start for preview deployments during the beta. Deploy to production or run the image locally.
  3. Ignored scaling change: a dashboard scaling override wins over
    instances
    until it is cleared.
  4. Unsafe overlap: old and new versions run side by side during a rollout. Keep message formats and schema migrations backward compatible.
  5. No SIGTERM handling: the process is killed 10 seconds after
    SIGTERM
    . Make jobs idempotent and acknowledge only after completion.
  6. Shell syntax in
    command
    :
    $VAR
    and
    &&
    are not expanded. Wrap in
    sh -c
    .
  7. Monorepo root directory: projects with a subfolder root directory cannot add daemons yet.
  8. Stale OIDC SDK: use
    @vercel/oidc
    ≥ 4.0.0 or
    vercel-oidc
    ≥ 0.10.0 so the token file is read.
  1. 期望接收流量:监听端口的 daemon 不会收到任何内容。请使用 Functions 或 Services 提供请求服务,并让 daemon 拉取工作。
  2. 在 preview 上测试:Beta 期间 daemons 永远不会为 preview 部署启动。请部署到生产环境或在本地运行镜像。
  3. 扩缩容更改被忽略:控制台中的扩缩容覆盖配置优先于
    instances
    ,直到将其清除。
  4. 不安全的重叠运行:滚动发布期间,旧版本和新版本会并行运行。请保持消息格式和 schema migration 向后兼容。
  5. 未处理 SIGTERM:进程会在收到
    SIGTERM
    10 秒后被终止。请让任务具备幂等性,并且仅在完成后确认消息。
  6. 在
    command
    中使用 shell 语法
    :
    $VAR
    和
    &&
    不会被展开。请使用
    sh -c
    包裹。
  7. Monorepo 根目录:根目录为子文件夹的项目目前无法添加 daemons。
  8. OIDC SDK 过旧:请使用
    @vercel/oidc
    ≥ 4.0.0 或
    vercel-oidc
    ≥ 0.10.0,以便读取 token 文件。

References

参考资料