---
title: The Complete Guide to Vercel Daemons
description: Run background workers with Vercel Daemons. Learn how to deploy container images, configure resources, handle shutdowns, and manage instances.
url: "https://vercel.com/kb/guide/vercel-daemons"
published: 2026-10-15
last_updated: 2026-10-15
authors: Ben Sabic
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Vercel Daemons runs containerized background processes in the same project as your app. Queue consumers, workflow workers, and self-hosted CI runners can stay running and pull their own work as it arrives.

Declare daemons in `vercel.json` to deploy them with your frontend and backend. Vercel builds each container image, starts its instances with your production deployment, and maintains the configured count in each region.

> Vercel Daemons is available in [Public Beta](https://vercel.com/docs/release-phases#public-beta) on [all plans](https://vercel.com/docs/plans).

## What is a Vercel Daemon?

Each Vercel Daemon is a named resource in your project that runs one or more instances of the same container. Each instance is an identical, interchangeable copy of your process, and Vercel restarts any instance that exits or crashes. Daemons run on [Fluid compute](https://vercel.com/docs/fluid-compute), the same compute platform as Vercel Functions.

Daemons don't receive traffic. Instead, each daemon pulls its own work from another system, such as a queue, a workflow engine, a database of pending jobs, or an external API. [Vercel Services](https://vercel.com/docs/services) handle routed workloads that respond to requests, while Vercel Daemons handle workloads that run continuously in the background.

## How Vercel Daemons work

Vercel manages each daemon through five stages, from build to shutdown:

1. **Build**: During the build, Vercel builds each daemon's `Dockerfile` or `Containerfile` and pushes the image to [Vercel Container Registry](https://vercel.com/docs/container-registry) as a repository named `daemon.<name>`.
   
2. **Deploy**: When the deployment becomes your production deployment, Vercel starts the requested number of instances in each region and stops the instances from the previous production deployment.
   
3. **Run**: Vercel restarts instances that exit or crash, and collects each instance's `stdout` and `stderr` output as logs.
   
4. **Scale**: You can override a daemon's instance counts from the dashboard without a new deployment. Overrides stay in place across deployments until you clear them.
   
5. **Stop:** Vercel sends `SIGTERM` before stopping or replacing an instance, allowing 10 seconds by default to finish work before a forced stop.
   

Changing a daemon's container image, command, or environment variables requires a new production deployment. You can adjust instance counts from the dashboard without deploying again.

Daemons run only in the production environment during the beta. Preview deployments don't start daemons.

## When should you use a daemon?

Use a Vercel Daemon when your process owns a continuous loop and decides when to do work. Common examples include:

- Consumers polling [Vercel Queues](https://vercel.com/docs/queues/poll-mode), Amazon SQS, Kafka, or Redis
  
- Workflow workers, such as Celery, Sidekiq, and BullMQ workers
  
- Job runners, such as self-hosted CI runners that wait for jobs
  
- Media processors that pull uploaded files from a queue and process them with system tools such as `ffmpeg`
  

Choose the product based on how your workload starts and runs:

| Workload                                       | Use                                                                                                          |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Responds to HTTP requests                      | [Vercel Functions](https://vercel.com/docs/functions) or [Vercel Services](https://vercel.com/docs/services) |
| Runs on a schedule                             | [Cron Jobs](https://vercel.com/docs/cron-jobs)                                                               |
| Processes messages that Vercel delivers to you | [Vercel Queues](https://vercel.com/docs/queues) in push mode                                                 |
| Runs multi-step, durable logic                 | [Vercel Workflows](https://vercel.com/docs/workflows)                                                        |
| Runs untrusted or per-user code in isolation   | [Vercel Sandbox](https://vercel.com/docs/sandbox)                                                            |
| Runs continuously and pulls its own work       | Vercel Daemons                                                                                               |

## Prerequisites

Before you add a daemon to your project, make sure you have:

- Your project's [root directory](https://vercel.com/docs/builds/configure-a-build#root-directory) set to the repository root. Subfolders such as `apps/web` aren't supported during the beta.
  
- Permission to deploy to production, where daemons run during the beta.
  
- [Docker](https://docs.docker.com/get-docker/) installed if you plan to test daemons locally.
  
- The [Vercel CLI](https://vercel.com/docs/cli) installed, if you want to deploy from your terminal.
  

## How to deploy your first daemon

Add a Node.js worker to your existing project and run two instances in `iad1`. The finished project will have this structure:

```text
my-app/
├── vercel.json
├── ...your app code
└── worker/
    ├── Dockerfile
    ├── package.json
    ├── package-lock.json
    └── worker.js
```

### 1\. Write the worker process

Create a `worker/` directory in your project for the daemon's source code. The following worker logs the region it runs in, waits for work in a loop, and exits cleanly when Vercel sends `SIGTERM`:

```javascript
const shutdown = new AbortController();

process.on('SIGTERM', () => shutdown.abort());

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function main() {
  console.log(`Worker started in ${process.env.VERCEL_REGION ?? 'local'}`);

  while (!shutdown.signal.aborted) {
    // Replace this with one unit of work, for example a long-polling
    // queue receive that stops when `shutdown.signal` aborts.
    console.log('Waiting for work...');
    await sleep(5000);
  }

  console.log('Received SIGTERM, shutting down');
  process.exit(0);
}

main();
```

The worker checks for shutdown after each 5s sleep, which normally leaves time to exit within the default 10s grace period. Delayed event-loop callbacks can still push shutdown past that deadline.

Replace the sleep with your worker's job-handling logic. Include a wait or backoff when no work is available so the loop doesn't spin.

Add a `package.json` to the same directory:

```json
{
  "name": "worker",
  "version": "1.0.0",
  "private": true
}
```

Then run `npm install` in `worker/` to generate `package-lock.json`, which the `Dockerfile` in the next step uses with `npm ci`:

```bash
cd worker
npm install
cd ..
```

### 2\. Add a Dockerfile

Every daemon needs a container image definition. Add a `Dockerfile` to `worker/`:

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

Vercel uses the directory that contains the `Dockerfile` as the build context, so `COPY . .` copies the contents of `worker/` into the image. Vercel builds the image for the Linux `amd64` architecture.

### 3\. Declare the daemon in vercel.json

Add the `daemons` key to `vercel.json` at the root of your project. This configuration declares a daemon named `worker` that builds from `worker/Dockerfile` and runs two instances in the `iad1` region:

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 2 }
    }
  }
}
```

Declare the same daemon in `vercel.toml` with a `[daemons.<name>]` table:

```text
[daemons.worker]
root = "worker/"
entrypoint = "Dockerfile"
instances = { iad1 = 2 }
```

### 4\. Deploy to production

Daemons start only when a deployment becomes your production deployment. Push to your production branch, or deploy from the Vercel CLI:

```bash
vercel --prod
```

When the production deployment is ready, Vercel starts two instances of `worker` in `iad1`.

### 5\. Confirm the daemon is running

Open your project's dashboard and select **Daemons**, then select `worker` to see its instances and their logs. Daemon output also appears in your project's [Logs](https://vercel.com/docs/logs/runtime) with the source `daemon` and the daemon's name. Each instance logs output like this:

```text
Worker started in iad1
Waiting for work...
Waiting for work...
```

## How to run a daemon alongside your app

Vercel Daemons don't change how Vercel builds the rest of your project. You can add the `daemons` key to a project that uses a framework such as Next.js, or to a project that uses [Vercel Services](https://vercel.com/docs/services). Always declare daemons at the top level of your configuration, not inside a service.

Keep each daemon's code in its own directory, such as `worker/` or `processor/`. Vercel doesn't publish files under a daemon's `root` as static assets of your deployment, and the build fails if your project's output directory is the same directory as a daemon's `root`.

### Example: process uploaded videos in the background

Video apps can use a daemon to prepare a playback copy and thumbnail for each uploaded clip. The Next.js frontend accepts uploads and sends a job to [Vercel Queues](https://vercel.com/docs/queues/poll-mode), and a Python processor running as a daemon pulls each job from the queue and processes the clip with `ffmpeg`.

Place the Python processor and its `requirements.txt` in `processor/`, then add this Dockerfile to install `ffmpeg` and the Python dependencies:

```docker
FROM python:3.12-slim
RUN apt-get update \
    && apt-get install -y --no-install-recommends ffmpeg \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY processor.py .
CMD ["python", "processor.py"]
```

Add the `daemons` key to your existing `vercel.json` to run the processor alongside Next.js. The app still builds and deploys as before.

To accommodate the processor's memory-intensive work, this configuration requests 4 GiB of memory and 2 vCPUs per instance:

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "videos": {
      "root": "processor/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 1 },
      "resources": { "requests": { "memory": "4Gi" } }
    }
  }
}
```

### Example: add a daemon to a project that uses Vercel Services

In a project with multiple Vercel Services, declare `daemons` next to `services` and `rewrites`. This configuration routes requests to a `web` service and an `api` service, and runs one `worker` instance in each of the `iad1` and `sfo1` regions:

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "services": {
    "web": { "root": "web/" },
    "api": { "root": "api/", "entrypoint": "main:app" }
  },
  "rewrites": [
    { "source": "/api/(.*)", "destination": { "service": "api" } },
    { "source": "/(.*)", "destination": { "service": "web" } }
  ],
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "command": ["node", "worker.js"],
      "instances": { "iad1": 1, "sfo1": 1 },
      "resources": { "requests": { "memory": "4Gi" } }
    }
  }
}
```

Daemons can't be the target of a [service binding](https://vercel.com/docs/services/bindings) or a rewrite, because a daemon doesn't accept inbound traffic.

## How to configure a daemon

The top-level `daemons` key in `vercel.json` is an object that maps each daemon name to its configuration. Each daemon configuration object supports these fields:

| Parameter    | Type                     | Required | Default                            |
| ------------ | ------------------------ | -------- | ---------------------------------- |
| `root`       | `string`                 | Yes      | None                               |
| `entrypoint` | `string`                 | Yes      | None                               |
| `instances`  | `Record<string, number>` | Yes      | None                               |
| `command`    | `string[]`               | No       | The image's `ENTRYPOINT` and `CMD` |
| `resources`  | `object`                 | No       | 2 GiB memory, 1 vCPU               |

Vercel rejects any other field, including service fields such as `framework`, `runtime`, `buildCommand`, and `bindings`.

### Daemon naming rules

Each key in `daemons` names a daemon and can contain up to 64 characters. Use lowercase letters with optional separators between groups: a single underscore `_`, a double underscore `__`, or one or more hyphens `-`.

For example, `worker`, `email_sender`, and `celery-beat` are valid names. Names such as `Worker`, `worker1`, and `_worker` are invalid.

Vercel stores each daemon's image in a repository named `daemon.<name>` and collapses repeated hyphens into one. Names such as `a-b` and `a--b` therefore map to the same repository and fail the build.

Daemon names and service names are independent. Your project can use the same name for a service and a daemon.

### root

The `root` field sets the path to the daemon's source directory, relative to `vercel.json`. The path must stay inside the project. Vercel doesn't publish files under a daemon's `root` as static assets, and the build fails if the project's output directory is the same directory as a daemon's `root`.

### entrypoint

The `entrypoint` field sets the path to the container image definition, relative to `root`. Name the file `Dockerfile` or `Containerfile`. The directory that contains the file is the build context, and Vercel passes your deployment's environment variables to the build as build arguments.

### instances

The `instances` field sets the number of instances to run in each region, keyed by [region ID](https://vercel.com/docs/regions). Each count is an integer from `0` to `100`, and Vercel runs instances only in the regions you list:

```json
{
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 2, "cdg1": 1 }
    }
  }
}
```

Set every count to `0` and deploy to production to stop a daemon without removing its configuration. If a dashboard scaling override is active, set its counts to `0` as well or clear it after the zero-count deployment becomes production.

### command

The `command` field sets the command and arguments to run in the container, as an array of strings. The `command` field replaces the image's `ENTRYPOINT` and `CMD`. When you don't set `command`, Vercel runs the image's `ENTRYPOINT` and `CMD`, and the build fails if the image defines neither.

This configuration runs a Celery worker from a shared backend image:

```json
{
  "daemons": {
    "celery": {
      "root": "backend/",
      "entrypoint": "Dockerfile",
      "command": ["celery", "-A", "app", "worker", "--loglevel=info"],
      "instances": { "iad1": 1 }
    }
  }
}
```

Vercel doesn't run `command` through a shell, so it doesn't expand environment variables. For shell expansion, use a command such as `["sh", "-c", "exec node worker.js --id \"$WORKER_ID\""]`. The quotes around `$WORKER_ID` keep its value in one argument.

The `command` array supports up to 128 items of up to 4,096 characters each.

### resources

The `resources` field sets the compute resources for each instance. Set `resources.requests.memory` to choose the memory, and Vercel allocates CPU based on that memory:

| `resources.requests.memory` | Memory | vCPUs |
| --------------------------- | ------ | ----- |
| `"1Gi"`                     | 1 GiB  | 1     |
| `"2Gi"` (default)           | 2 GiB  | 1     |
| `"4Gi"`                     | 4 GiB  | 2     |
| `"8Gi"`                     | 8 GiB  | 4     |

When you set `resources`, both `requests` and `memory` are required.

## How to handle graceful shutdown

Vercel sends `SIGTERM` to a daemon instance before stopping it, then force-stops the process if it's still running after 10s. Vercel stops instances when you deploy a new version, reduce the number of instances, or remove a daemon.

Handle `SIGTERM` by stopping new work and finishing any accepted job within the remaining grace period.

This TypeScript example uses an interruptible idle wait. Replace the timer in `processNextJob` with your queue client's receive, processing, and acknowledgement logic. The abort signal should cancel a pending receive before it accepts a job:

```typescript
import { setTimeout as sleep } from 'node:timers/promises';

const shutdown = new AbortController();

process.on('SIGTERM', () => shutdown.abort());

async function processNextJob(signal: AbortSignal): Promise<void> {
  // Replace this idle wait with an abort-aware queue receive.
  // Finish and acknowledge any accepted job before returning.
  await sleep(1000, undefined, { signal });
}

async function main(): Promise<void> {
  try {
    while (!shutdown.signal.aborted) {
      await processNextJob(shutdown.signal);
    }
  } catch (error) {
    if (
      !shutdown.signal.aborted ||
      !(error instanceof Error) ||
      error.name !== 'AbortError'
    ) {
      throw error;
    }
  }
}

void main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

Daemon instances can stop at any time, so make interrupted jobs safe to retry. Acknowledge queue messages only after processing succeeds, and make processing idempotent to avoid repeating side effects.

Redelivery depends on your queue's retry policy and message retention. With [Vercel Queues](https://vercel.com/docs/queues/concepts#visibility-timeout), an unacknowledged message becomes available again after its visibility timeout expires, as long as the message hasn't expired.

Instances from the previous deployment can continue processing work during the shutdown grace period as new instances start.

Make sure both versions can process the same work during this overlap, such as messages from the same queue.

## How daemons access environment variables and OIDC tokens

Each daemon instance receives your deployment's [environment variables](https://vercel.com/docs/environment-variables), plus `VERCEL_REGION`, which Vercel sets to the region the instance runs in. Vercel also passes the same environment variables to the image build as build arguments.

Each daemon instance gets a [Vercel OIDC token](https://vercel.com/docs/oidc) to authenticate with other services without storing long-lived credentials. Vercel writes the token to the path in `VERCEL_OIDC_TOKEN_FILE` and periodically replaces the file with a fresh token.

JavaScript apps need `@vercel/oidc` 4.0 or later because earlier versions can't read token files. Python apps can use the `vercel-oidc` package.

## How to run a daemon locally

The `vercel dev` command doesn't run daemons. When your configuration contains `daemons`, `vercel dev` prints a warning and starts the rest of your project, so run each daemon with Docker instead.

The starter worker doesn't require application environment variables. If your worker needs them, add its development values to an `.env.docker` file at the project root.

Use one unquoted `KEY=value` pair per line. Replace these example names and values with your worker's settings, and exclude the file from version control:

```text
QUEUE_URL=https://your-queue.example
QUEUE_TOKEN=your-development-token
```

Build and run the starter from your project root. To load development credentials, add `--env-file .env.docker` before the image name in `docker run`:

```bash
docker build -t worker worker/
docker run --rm --name worker worker
```

The worker from the first section logs `local` as its region, because `VERCEL_REGION` isn't set outside Vercel:

```text
Worker started in local
Waiting for work...
```

To test graceful shutdown, run `docker stop worker` in another terminal. The `docker stop` command sends `SIGTERM` and waits 10s before force-stopping the container, which matches how Vercel stops daemon instances by default.

## How to deploy changes to a daemon

Vercel updates daemons when a deployment becomes your production deployment. This happens when you deploy to production, [promote a deployment](https://vercel.com/docs/deployments/promoting-a-deployment), use [Instant Rollback](https://vercel.com/docs/instant-rollback), or complete a [rolling release](https://vercel.com/docs/rolling-releases).

- **New or changed daemons:** Vercel sends `SIGTERM` to the previous production deployment's instances and immediately starts instances from the new image.
  
- **Removed daemons**: When the new production deployment doesn't declare a daemon, Vercel stops all of that daemon's instances.
  
- **Rollbacks**: Rolling back restores the daemons, images, and instance counts that the earlier deployment declared. If a daemon has a scaling override, the override's instance counts stay in place.
  

## How to scale a daemon

Each Vercel Daemon runs a fixed number of instances in each region, and Vercel doesn't autoscale daemons. You can set instance counts in `vercel.json` or override them from the dashboard.

### Scale with vercel.json

To change the number of instances, set `instances` to a new map of region IDs to instance counts, then deploy to production:

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 3, "cdg1": 2 }
    }
  }
}
```

The new map replaces the previous map, so regions that you remove from `instances` stop their instances.

### Scale from the dashboard

To change a daemon's instance counts without a new deployment:

1. In your project's dashboard, select **Daemons**, then select the daemon.
   
2. Select **Set Scaling Overrides**.
   
3. Set the number of instances in each region, then select **Scale Daemon**.
   

Instance counts set in the dashboard are a scaling override that takes precedence over the `instances` configuration in your production deployment. The override persists across deployments, so changes to `instances` in `vercel.json` have no effect while it is set.

To return to the counts from your production deployment, open **Set Scaling Overrides** and select **Clear scaling overrides**.

You need permission to update the project to set scaling overrides.

## How to stop or delete a daemon

Vercel gives you three ways to stop a daemon, depending on whether you want to keep its configuration:

- **Stop without deploying:** Override all regional instance counts to `0`.
  
- **Stop and keep the configuration:** Set every region in `instances` to `0` and deploy to production. If a scaling override is active, set its counts to `0` or clear it after the zero-count deployment becomes production.
  
- **Delete the daemon**: Remove the daemon from `daemons` in `vercel.json`, then deploy to production.
  

This configuration retains the `worker` daemon with zero instances declared:

```json
{
  "daemons": {
    "worker": {
      "root": "worker/",
      "entrypoint": "Dockerfile",
      "instances": { "iad1": 0 }
    }
  }
}
```

When a project is [paused](https://vercel.com/docs/projects/managing-projects#pausing-a-project), for example by [spend management](https://vercel.com/docs/spend-management#pausing-projects), Vercel stops all of the project's daemon instances. The daemon instances start again when you resume the project.

## How to view daemon logs

Vercel collects each daemon instance's `stdout` and `stderr` in your project's [Logs](https://vercel.com/docs/logs/runtime). Filter by the source `daemon` and the daemon's name to view its output.

To view instances and their logs together, open **Daemons** in your project's dashboard and select the daemon.

## What are the limits for Vercel Daemons during the beta?

The following limits apply to Vercel Daemons during the beta, and Vercel may raise them as the beta progresses.

### Configuration limits

| Limit                          | Value                                  |
| ------------------------------ | -------------------------------------- |
| Daemon name length             | 64 characters                          |
| `root` and `entrypoint` length | 512 characters each                    |
| `command` items                | 128 items, up to 4,096 characters each |
| Instances per region           | 100 per daemon                         |

### Instance limits

| Limit                 | Value                                           |
| --------------------- | ----------------------------------------------- |
| Memory per instance   | 1 GiB, 2 GiB, 4 GiB, or 8 GiB (default 2 GiB)   |
| vCPUs per instance    | 1, 1, 2, or 4, based on memory                  |
| Shutdown grace period | 10s after `SIGTERM` by default                  |
| CPU architecture      | Linux `amd64`                                   |
| Image source          | `Dockerfile` or `Containerfile` in your project |

### Hobby plan usage

The [Hobby plan](https://vercel.com/docs/plans/hobby) gives daemons across all of a team's projects 10 vCPU-hours per month. Each instance uses vCPU-hours for as long as it runs, so one 1-vCPU instance uses the allowance in about 10 hours.

Use Hobby to try daemons and the [Pro plan](https://vercel.com/docs/plans/pro-plan) for workers that need to run all month.

When a Hobby team reaches the allowance, Vercel stops all of the team's daemon instances and logs an error. The daemons start again at the beginning of the next month, or when you upgrade the team to Pro.

### Unsupported features

Vercel Daemons don't support the following features during the beta:

| Feature                           | Alternative                                                                                                                                              |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Preview deployments               | Daemons run only in production. Test changes by [running the daemon's image locally](#how-to-run-a-daemon-locally).                                      |
| Inbound HTTP or TCP traffic       | Use [Vercel Services](https://vercel.com/docs/services) or [Vercel Functions](https://vercel.com/docs/functions) for workloads that respond to requests. |
| Autoscaling                       | Set instance counts in your configuration or from the dashboard.                                                                                         |
| Persistent local storage          | Store state in [Vercel Blob](https://vercel.com/docs/vercel-blob) or a database from the [Marketplace](https://vercel.com/docs/marketplace-storage).     |
| Running in `vercel dev`           | Run the daemon's image locally with Docker.                                                                                                              |
| Service bindings and rewrites     | Daemons can't be the target of a service binding or a rewrite.                                                                                           |
| Builds without a Dockerfile       | Add a `Dockerfile` or `Containerfile` to the daemon's `root`.                                                                                            |
| Root directory set to a subfolder | Projects with a root directory such as `apps/web` can't add daemons yet.                                                                                 |

## Troubleshooting

### The build fails with two daemon names that map to the same repository

Vercel collapses repeated hyphens when it names each image repository, so daemon names such as `a-b` and `a--b` both map to `daemon.a-b` and fail the build. Rename one of the daemons so the names stay distinct after collapsing hyphens.

### The build fails because the output directory matches a daemon's root

The build fails when your project's output directory is the same directory as a daemon's `root`, because Vercel doesn't publish files under a daemon's `root` as static assets. Move the daemon's code into its own directory, such as `worker/`, or choose a separate output directory for your app.

### The build fails because the image has no command to run

Every daemon image needs a command to run. Add a `CMD` or `ENTRYPOINT` to the `Dockerfile`, or set the `command` field in the daemon's configuration.

### Changes to instances in vercel.json don't take effect

Scaling overrides set from the dashboard take priority over the `instances` in your production deployment and stay in place across deployments. Open the daemon in your project's dashboard, select **Set Scaling Overrides**, then select **Clear scaling overrides** to return to the counts in `vercel.json`.

### Daemons don't run in preview deployments

Daemons run only in the production environment during the beta, so preview deployments don't start daemons. Test daemon changes locally with Docker, then deploy to production.

### The vercel dev command prints a warning about daemons

The `vercel dev` command doesn't run daemons and prints a warning when your configuration contains `daemons`. The rest of your project still starts, so run each daemon separately with `docker build` and `docker run`.

### Daemon instances can't read the OIDC token

Vercel provides the OIDC token to daemon instances as a file referenced by `VERCEL_OIDC_TOKEN_FILE`, and versions of `@vercel/oidc` earlier than 4.0 can't read the token file. Upgrade to `@vercel/oidc` 4.0 or later for JavaScript, or use the `vercel-oidc` package for Python.

### All daemons stopped on a Hobby team

Daemons on a Hobby team stop when the team uses its 10 vCPU-hours for the month, and Vercel logs an error when this happens. The daemons start again at the beginning of the next month, or immediately when you upgrade the team to Pro.

### All daemons stopped after the project was paused

Vercel stops a project's daemon instances when the project is paused, including when spend management pauses it. Resume the project to restart its daemons.

### You can't add daemons when the project root is a subfolder

Projects with a root directory set to a subfolder, such as `apps/web`, can't add daemons during the beta. Daemons are available for projects whose root directory is the repository root.

## Next steps

- Read the [Vercel Daemons documentation](https://vercel.com/docs/daemons) for the latest beta details.
  
- Look up every field in the [Daemon configuration reference](https://vercel.com/docs/daemons/config-reference).
  
- Learn how to scale, stop, and monitor daemons in [Managing daemons](https://vercel.com/docs/daemons/managing-daemons).
  
- Review the current [Daemons limits](https://vercel.com/docs/daemons/limits).
  
- Consume messages from a daemon with [Vercel Queues poll mode](https://vercel.com/docs/queues/poll-mode).
  
- [Deploy container images in Vercel Functions](https://vercel.com/docs/functions/container-images) for apps that respond to requests.
  
- See how daemons appear in the [Build Output API](https://vercel.com/docs/build-output-api/daemons).