---
title: Running Docker on Vercel
description: Run Docker on Vercel for HTTP apps and background workers, store images in Vercel Container Registry, and test containers with Vercel Sandbox.
url: "https://vercel.com/kb/guide/docker"
published: 2026-07-01
last_updated: 2026-10-29
authors: Ben Sabic
related_resources:
  - title: "The Complete Guide to Vercel Services"
    url: "https://vercel.com/kb/guide/vercel-services"
    description: "Vercel Services let you deploy multiple frontends and backends in one project on a shared domain. Learn how to define services in vercel.json, route requests by path prefix, and connect services with generated environment variables."
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Vercel supports Docker for HTTP applications, continuous background workers, testing, and local development. Deploy an OCI (Open Container Initiative) container image as an autoscaling Vercel Function on [Fluid compute](https://vercel.com/fluid), or run a continuous worker with [Vercel Daemons](https://vercel.com/docs/daemons).

You can also store images in [Vercel Container Registry](https://vercel.com/docs/container-registry) (VCR), run containers inside [Vercel Sandbox](https://vercel.com/docs/sandbox/concepts/runtimes) for testing, and use Docker locally to keep builds reproducible.

| Where Docker fits         | What it's for                                                     |
| ------------------------- | ----------------------------------------------------------------- |
| Vercel Functions          | Ship a containerized app with autoscaling and Active CPU pricing  |
| Vercel Daemons            | Run continuous background workers with configured instance counts |
| Vercel Container Registry | Store, push, and pull OCI images for functions and sandboxes      |
| Vercel Sandbox            | Test images and run containerized dependencies in isolation       |
| Local Development         | Reproduce builds and test container images before deploying       |

## Deploy a container image as a Vercel Function

The main way to run Docker on Vercel is to deploy a container image as a [Vercel Function](https://vercel.com/docs/functions). Add a `Dockerfile` or `Containerfile` to your project root, and Vercel builds the image, stores it in VCR, and serves it from a Function that scales automatically with traffic.

The Function scales to zero when idle and uses [Fluid compute pricing](https://vercel.com/docs/functions/usage-and-pricing) for active CPU time, provisioned memory, and invocations. CPU billing pauses while your code waits for I/O. The Container runtime is in beta on all plans.

Reach for this when framework detection can't cover your app:

- It depends on a system library such as FFmpeg or Chromium
  
- It uses a framework Vercel doesn't auto-detect yet
  
- It needs to run exactly as it does elsewhere
  

### Add a Dockerfile

When Vercel detects no other framework, it builds the `Dockerfile` at your project root and adds a rewrite that routes all traffic to the resulting image. If project detection matches a framework such as Next.js or Django, that framework wins. To build the `Dockerfile` instead, run `vercel project update --framework container` or set `"framework": "container"` in `vercel.json`. A `Dockerfile.vercel` or `Containerfile.vercel` also works and takes precedence over a detected framework.

Here's a minimal dynamic server using Node.js and the `srvx` server:

```docker
FROM node:26-alpine

RUN npm i -g srvx
WORKDIR /app
COPY server.ts .

# srvx listens on $PORT by default
CMD ["srvx", "--prod"]
```
```typescript
export default {
  fetch(req: Request) {
    return Response.json({ ip: req.headers.get("x-forwarded-for") })
  }
}
```

Static servers work the same way with a `Dockerfile` that starts with `FROM nginx:alpine` and copies your static files into `/usr/share/nginx/html`. Deploy either kind by running `vercel deploy` or by pushing to a connected Git repository.

### Run multiple services in one project

To deploy more than one application in a single project, define each one as a service and use `rewrites` in `vercel.json` to route incoming requests to it. Set each service's `entrypoint` to its Dockerfile path, relative to the service's `root`:

```json
{
  "services": {
    "frontend": {
      "root": "frontend/",
      "entrypoint": "Dockerfile"
    },
    "backend": {
      "root": "backend/",
      "entrypoint": "Dockerfile"
    }
  },
  "rewrites": [
    { "source": "/api/(.*)", "destination": { "service": "backend" } },
    { "source": "/(.*)", "destination": { "service": "frontend" } }
  ]
}
```

### Key behaviors

| Behavior           | What to expect                                                                                                                                                                                                                                                                                                                                          |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Port Resolution    | Containers serve HTTP traffic on port `80` by default. Override it with the `PORT` environment variable in [project settings](https://vercel.com/d?to=%2F%5Bteam%5D%2F%5Bproject%5D%2Fsettings%2Fenvironment-variables).                                                                                                                                |
| Scale-in           | Functions that receive no traffic for five minutes in production or 30 seconds in preview scale down. On scale-down, the container receives `SIGTERM` with a 30-second grace period before termination.                                                                                                                                                 |
| Observability      | Vercel broadcasts `stdout` and `stderr` logs to all inflight requests on the instance, and [Vercel Observability](https://vercel.com/docs/observability) metrics work like any other function.                                                                                                                                                          |
| Pricing and Limits | Container image functions use [Fluid compute pricing](https://vercel.com/docs/functions/usage-and-pricing) and follow [Vercel Function limits](https://vercel.com/docs/functions/limitations). [Secure Compute and Static IPs are not supported](https://vercel.com/docs/functions/runtimes/container#limits-and-pricing) with custom container images. |

## Run continuous workers with Vercel Daemons

Use [Vercel Daemons](https://vercel.com/docs/daemons) for a process that keeps retrieving work, such as a queue consumer. Vercel builds its image from a Dockerfile or Containerfile and maintains the configured instance count, restarting processes that exit. Daemons can run alongside the HTTP services in your project.

During the beta, Daemons run only in production and do not support autoscaling, inbound HTTP or TCP traffic, or persistent local storage. Check the [limits and plan quotas](https://vercel.com/docs/daemons/limits) before choosing instance counts. Memory usage continues while a daemon waits for work.

For a migration walkthrough, use the dedicated guide for [Render background workers](https://vercel.com/kb/guide/migrate-render-workers-to-vercel-daemons) or [Railway workers](https://vercel.com/kb/guide/migrate-railway-workers-to-vercel-daemons).

## Store images in Vercel Container Registry

Vercel Container Registry (VCR) is a project-scoped registry for OCI images, hosted at `vcr.vercel.com`. It supports the Docker Registry HTTP API v2, so `docker push`, `docker pull`, and `docker tag` work without new tooling. Full image references include the registry host, team slug, project slug, repository name, and tag:

```text
vcr.vercel.com/team-slug/project-slug/my-repository:latest
```

Vercel provides `VERCEL_OIDC_TOKEN` automatically in deployments. For local use, install the [Vercel CLI](https://vercel.com/docs/cli), Docker, and Docker Buildx, then run these commands from the directory containing your `Dockerfile`:

```bash
vercel link
vercel vcr login docker
vercel vcr build docker . my-repository:latest --push
```

The CLI authenticates Docker for the linked project, builds the image for `linux/amd64`, and pushes it to VCR. With Buildx installed, it also applies the recommended zstd compression. If your file is named `Dockerfile.vercel`, add `-- -f Dockerfile.vercel` to the build command.

Once an image is in VCR, both Vercel Functions and Vercel Sandbox can use it. The [registry documentation](https://vercel.com/docs/container-registry) covers authentication, build options, and limits.

## Run Docker with Vercel Sandbox

Vercel Sandbox gives you an isolated Linux environment for safely running untrusted or user-generated code, and it works with Docker in two ways:

- You can install and run the Docker engine inside a sandbox
  
- You can boot a sandbox directly from a custom image in VCR
  

### Run Docker inside a sandbox

Sandboxes can install and run Docker, allowing you to build images and run containers without touching your host system. Each sandbox is a Firecracker microVM with its own kernel and filesystem, and it runs with `sudo` access, which is what lets you start the Docker daemon inside it.

This is useful for running containerized services like Redis or Postgres as test dependencies, validating an image before you deploy it, or previewing an app served from a container.

Follow the [Sandbox quickstart](https://vercel.com/docs/sandbox/quickstart) to install the SDK and configure authentication. This example installs Docker in an Ubuntu sandbox, waits for the daemon, and runs Docker's test container:

```typescript
import { config } from "dotenv";
import { Sandbox } from "@vercel/sandbox";

config({ path: ".env.local" });

async function main() {
  const sandbox = await Sandbox.create({
    image: "vercel/sandbox/ubuntu:latest",
    persistent: false,
  });

  try {
    const result = await sandbox.runCommand({
      sudo: true,
      cmd: "bash",
      args: [
        "-euc",
        `
apt-get update
apt-get install -y docker.io
dockerd >/tmp/dockerd.log 2>&1 &
timeout 30s sh -c 'until docker info >/dev/null 2>&1; do sleep 1; done'
docker run --rm hello-world
`,
      ],
      stdout: process.stdout,
      stderr: process.stderr,
    });

    if (result.exitCode !== 0) {
      throw new Error(`Docker setup or test failed: ${result.exitCode}`);
    }
  } finally {
    await sandbox.stop();
  }
}

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

Run `pnpm tsx run-docker.ts`. The test container prints a confirmation message before the sandbox stops. `sudo: true` provides the privileges needed to install Docker and run its daemon.

This example disables persistence for a one-off test. For repeated work, [persistent sandboxes](https://vercel.com/changelog/sandbox-persistence-is-now-ga) retain the Docker installation and pulled images when you resume the same sandbox. Restart the daemon and any containers after resuming; running processes do not survive between sessions.

Containers use their own filesystem and trust store, so they don't inherit the sandbox's proxy CA certificate. The sandbox host already trusts the certificate mounted at `/etc/pki/ca-trust/source/anchors/vercel-proxy-ca.pem`.

When the [sandbox firewall](https://vercel.com/docs/sandbox/concepts/firewall#tls-termination) terminates HTTPS connections for `transform` or `forwardURL` rules, containers must trust that certificate to pass TLS verification. Mount the certificate into the container and update its trust store during the build or when the container starts:

```bash
docker run --rm \
  -v /etc/pki/ca-trust/source/anchors/vercel-proxy-ca.pem:/usr/local/share/ca-certificates/vercel-proxy-ca.crt:ro \
  my-image \
  sh -c "update-ca-certificates && my-command"
```

The exact location and trust-update command depend on the base image: use `update-ca-certificates` on Debian or Ubuntu, and `update-ca-trust` on Amazon Linux, Fedora, or RHEL. If your app reads a CA bundle from an environment variable instead of the system trust store, point that variable (such as `NODE_EXTRA_CA_CERTS`) at the mounted certificate path inside the container.

### Boot a sandbox from a custom image

To define the sandbox environment itself with Docker, [build and push a custom image to VCR](https://vercel.com/docs/sandbox/concepts/images#custom-images). The image must target `linux/amd64` and reach the **Ready** state in VCR before Sandbox can use it. The repository name below resolves within the project used to authenticate the SDK:

```typescript
import { Sandbox } from "@vercel/sandbox";

const sandbox = await Sandbox.create({
  image: "my-repository:latest",
});
```

The sandbox boots with your image's packages and tools already in place. It does not run the Dockerfile's `ENTRYPOINT` or `CMD`; start your process with `sandbox.runCommand()` after creation. If creation returns `image_not_ready`, wait for VCR to finish preparing the image and retry.

## Use Docker for local development

To develop and test a container image before deploying, run `vercel dev`, which needs the `docker` CLI and a running Docker daemon on your machine.

Even for zero-configuration frameworks you deploy without a container, a Dockerfile can pin dependencies and give you a consistent build environment across machines. The [Next.js Dockerfile example](https://github.com/vercel/next.js/tree/canary/examples/with-docker) shows how to build and run a standalone production image locally.

For a framework app deployed without a custom container image, you can also check the Vercel build locally. Run `vercel pull` to refresh your project settings and environment variables, then `vercel build`. After a successful build, `vercel deploy --prebuilt` uploads the generated `.vercel/output` artifacts without uploading the project's source code.

## Resources and next steps

- See the [Container Images documentation](https://vercel.com/docs/functions/container-images) for configuration details, including Services and `rewrites`.
  
- Learn how to store, push, and pull images in [Vercel Container Registry](https://vercel.com/docs/container-registry).
  
- Explore [Vercel Sandbox](https://vercel.com/docs/sandbox) to build and test containers in an isolated environment.
  
- Try the [Next.js Dockerfile example](https://github.com/vercel/next.js/tree/canary/examples/with-docker) for local development.
  
- Learn more about [Vercel Services](https://vercel.com/kb/guide/vercel-services) to run frontends and backends in one project.
  
- Use [Vercel Daemons](https://vercel.com/docs/daemons) for continuous background workers.

## Related Documentation

- [Vercel Services](https://vercel.com/docs/services)
- [Vercel Container Registry](https://vercel.com/docs/container-registry)
- [Vercel Sandbox](/docs/vercel-sandbox)

## Related Resources

- [The Complete Guide to Vercel Services](https://vercel.com/kb/guide/vercel-services): Vercel Services let you deploy multiple frontends and backends in one project on a shared domain. Learn how to define services in vercel.json, route requests by path prefix, and connect services with generated environment variables.

## More Vercel Services guides

- [Migrate from Railway to Vercel](/kb/guide/migrate-railway-to-vercel): Migrate an app from Railway to Vercel. Choose a deployment path, configure services, plan for stored data, and test before switching production traffic.
- [Migrate from Google Cloud Run to Vercel](/kb/guide/migrate-cloud-run-to-vercel): Move a Cloud Run service or worker to Vercel. Compare runtimes, preserve Google Cloud access, and plan jobs, validation, and production cutover.
- [Migrate from Render to Vercel](/kb/guide/migrate-render-to-vercel): Migrate from Render to Vercel: map web services, cron jobs, and containers to their equivalents, and handle what doesn't move.