# Running Docker on Vercel

**Author:** Ben Sabic

---

Vercel supports Docker across your whole workflow. You can deploy an application packaged as an OCI (Open Container Initiative) container image as an autoscaling Vercel Function on [Fluid compute](https://vercel.com/fluid), 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. Each path suits a different stage of building and shipping.

This guide will teach you how to run Docker on Vercel across every stage of building and shipping, from local development through to production.

Vercel works with Docker in a few distinct ways, depending on what you're trying to do:

| Where Docker fits         | What it's for                                                    |
| ------------------------- | ---------------------------------------------------------------- |
| Vercel Functions          | Ship a containerized app with autoscaling and Active CPU pricing |
| 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.vercel` (or `Containerfile.vercel`) to your project root, and Vercel builds the image, stores it in VCR, and serves it from a Function that scales automatically with traffic. You're billed only for the CPU your code actively uses, and the Function scales to zero when idle.

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

Vercel detects the `Dockerfile.vercel` at your project root and adds a rewrite that routes all traffic to the resulting image. Here's a minimal dynamic server using Node.js and the `srvx` server:

`FROM node:26-alpine RUN npm i -g srvx WORKDIR /app COPY server.ts . # srvx listens on $PORT by default CMD ["srvx", "--prod"]` `export default { fetch(req: Request) { return Response.json({ ip: req.headers.get("x-forwarded-for") }) } }` Static servers work the same way. A `Dockerfile.vercel` that starts `FROM nginx:alpine` and copies your files into `/usr/share/nginx/html` serves them as static content. 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 route traffic between them with `rewrites` in `vercel.json`. Set each service's `entrypoint` to its Dockerfile path, relative to the service's `root`: `{ "services": { "frontend": { "root": "frontend/", "entrypoint": "Dockerfile.vercel" }, "backend": { "root": "backend/", "entrypoint": "Dockerfile.vercel" } }, "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 follow the same Active CPU pricing model and limits as every other Vercel Function.                                                                                                            |

## 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. A full image reference includes the registry host, team slug, project slug, repository name, and tag:

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

Vercel provides `VERCEL_OIDC_TOKEN` automatically in deployments. For local use, run `vercel link` and `vercel env pull` to get the token, then authenticate and push:

`printf '%s' "$VERCEL_OIDC_TOKEN" | docker login vcr.vercel.com \ --username oidc \ --password-stdin docker push vcr.vercel.com/team-slug/project-slug/my-repository:latest`

Vercel recommends building with Docker Buildx and zstd compression for images you push to VCR. Once an image is in VCR, both Vercel Functions and Vercel Sandbox can use it. For authentication options, compression flags, and limits, see the [Vercel Container Registry documentation](https://vercel.com/docs/container-registry).

## 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.

Install Docker, start the daemon, then run a container:

`import { Sandbox } from "@vercel/sandbox"; const sandbox = await Sandbox.create(); await sandbox.runCommand({ sudo: true, cmd: "dnf", args: ["install", "-y", "docker"], }); // Start the Docker daemon and wait for it to be ready await sandbox.runCommand({ sudo: true, cmd: "dockerd", detached: true }); await sandbox.runCommand({ cmd: "sh", args: ["-lc", "until sudo docker info >/dev/null 2>&1; do sleep 1; done"], }); await sandbox.runCommand({ cmd: "docker", args: ["run", "--rm", "-d", "--name", "redis", "redis:alpine"], }); await sandbox.runCommand({ cmd: "docker", args: ["exec", "redis", "redis-cli", "PING"], });` Starting a container runtime needs system-level privileges, so run these commands with `sudo`. With [persistent sandboxes](https://vercel.com/changelog/sandbox-persistence-is-now-ga), the Docker installation and any pulled images carry over between sessions, so you skip setup on the next run.

One behavior to watch: a container you run inside a sandbox has its own filesystem and trust store, so it doesn't inherit the sandbox's proxy CA certificate. The sandbox host mounts that certificate at `/etc/pki/ca-trust/source/anchors/vercel-proxy-ca.pem` and trusts it automatically, but a container started inside the sandbox can't see it. As a result, HTTPS requests from inside the container fail TLS verification when the sandbox firewall terminates them.

To fix this, mount the certificate into the container and add it to the container's own trust store at build or run time:

`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, push your image to VCR and boot the sandbox from it instead of installing packages at runtime:

`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, rather than a built-in runtime. See [sandbox images](https://vercel.com/docs/sandbox/concepts/images) to learn how to build and push a custom image.

## Use Docker for local development

Docker also fits into 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 repository includes a [Dockerfile example](https://github.com/vercel/next.js/tree/canary/examples/with-docker) for this workflow. To verify a Vercel build locally without pushing code, run `vercel build`, then run `vercel deploy --prebuilt` to upload the output from `.vercel/output` without sending 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.

---

[View full KB sitemap](/kb/sitemap.md)
