---
title: How to use Vercel Container Registry
description: Push, store, and pull OCI container images with Vercel Container Registry, then deploy them to Vercel Functions and Vercel Sandbox.
url: "https://vercel.com/kb/guide/how-to-use-vercel-container-registry"
published: 2026-07-11
last_updated: 2026-10-22
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."
  - title: "Running Docker on Vercel"
    url: "https://vercel.com/kb/guide/docker"
    description: "Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox."
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

[Vercel Container Registry](https://vercel.com/docs/container-registry) (VCR) stores OCI container images in repositories attached to your Vercel project. Authenticate Docker to `vcr.vercel.com` to push images from your machine or build pipeline.

Vercel Sandbox can start from an image you push to VCR. With Vercel Functions, deploying a `Dockerfile.vercel` builds and pushes the image during deployment.

## Prerequisites

Before you begin, make sure you have:

- Access to the Vercel project you want to push images to
  
- [Docker](https://docs.docker.com/get-docker/) installed and running locally, with [Buildx](https://docs.docker.com/buildx/working-with-buildx/) for the zstd build option
  
- The latest [Vercel CLI](https://vercel.com/docs/cli), authenticated with `vercel login`
  
- Application source and a `Dockerfile` in the directory you'll build
  

## How it works

Every Vercel project has its own namespace in VCR. The full image reference combines the registry host, team slug, project name, and repository name, followed by a tag or digest:

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

VCR implements the Docker Registry HTTP API v2 with OCI media types, so standard Docker tools can push and pull images.

After a push, VCR prepares an optimized build for Vercel Sandbox. The image must finish that preparation before a sandbox can start from it.

## Steps

### 1\. Link your project

From your application's root directory, link the local directory to the Vercel project that will own the images:

```bash
vercel link
```

### 2\. Authenticate Docker with VCR

Authenticate Docker for the linked project:

```bash
vercel vcr login docker
```

Vercel passes Docker a project-scoped OpenID Connect (OIDC) token valid for 12 hours. Run the command again to refresh the credentials.

For GitHub Actions, follow [Push images from GitHub Actions](https://vercel.com/docs/container-registry/github-actions) to authenticate with a short-lived token and a Vercel team OIDC policy.

If your environment requires an account token, create one on the [Account Tokens page](https://vercel.com/account/tokens). Set `VERCEL_TOKEN` to the token value and `VERCEL_TEAM_ID` to the ID of the team that owns the project, then run:

```bash
printf '%s' "$VERCEL_TOKEN" | docker login vcr.vercel.com \
  --username "$VERCEL_TEAM_ID" \
  --password-stdin
```

### 3\. Build and tag the image locally

Tag the image with the full VCR path so `docker push` knows where to send it. Replace `team-slug` with the slug in your dashboard URL and `project-slug` with your project's name.

Build for `linux/amd64` so the image can also run in Vercel Sandbox. The final `.` uses the current directory as the build context and reads its `Dockerfile`:

```bash
docker build --platform linux/amd64 \
  -t vcr.vercel.com/team-slug/project-slug/my-repository:latest \
  .
```

If the repository doesn't exist yet, VCR creates it the first time you push, provided you have access to the project.

### 4\. Push the image to VCR

To push the image, use `docker push` with the tag you built:

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

For Vercel's recommended zstd compression, use this Buildx command as an alternative to the separate build and push commands above. It builds and pushes the `linux/amd64` image in one operation:

```bash
docker buildx build \
  --platform linux/amd64 \
  --output "type=image,name=vcr.vercel.com/team-slug/project-slug/my-repository:latest,push=true,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true" \
  .
```

If you also need an ARM image and your builder supports both architectures, set `--platform` to `linux/amd64,linux/arm64`.

### 5\. Pull the image for verification

Confirm that the image is available from VCR by pulling the same `linux/amd64` image back to your machine or into a CI job:

```bash
docker pull --platform linux/amd64 \
  vcr.vercel.com/team-slug/project-slug/my-repository:latest
```

Compare Docker's pull and push digests to confirm you retrieved the intended image. You can also browse tags and digests in your project's **Images** tab.

### 6\. Deploy a container-based function (optional)

To deploy an HTTP app from source, add its `Dockerfile.vercel` or `Containerfile.vercel` at the project root. Vercel builds a deployment image from those files, pushes it to VCR, and routes traffic to the resulting function.

Use the [Container Runtime example](https://vercel.com/docs/functions/runtimes/container#dockerfile) for a complete Dockerfile and app.

Deploy with `vercel deploy` or by pushing to a connected Git branch. The app must serve HTTP on port `80` by default. To use another port, set `PORT` in the project settings and configure your server to listen on that value.

Container-based functions use [Fluid compute pricing](https://vercel.com/docs/functions/usage-and-pricing) for active CPU, provisioned memory, and invocations. Check the [function limits](https://vercel.com/docs/functions/limitations) before deploying.

Secure Compute and Static IPs are not supported with custom container images.

### 7\. Reference the image from Vercel Sandbox

Use the repository and tag from the linked project. Docker login authenticates your container tool; the Sandbox SDK needs project credentials separately.

In a Node.js 22+ project, install the SDK and download an OIDC token:

```bash
npm install @vercel/sandbox
vercel env pull .env.local
```

You can also [authenticate with an access token](https://vercel.com/docs/sandbox/concepts/authentication#access-tokens) by passing `teamId`, `projectId`, and `token` to `Sandbox.create()`.

Sandbox requires an optimized `linux/amd64` image. Wait for **Ready** on the repository details page before running the example.

Rebuild **Unoptimized** images for `linux/amd64`. If creation returns `image_not_ready`, wait for **Ready** before retrying.

Save the following as `sandbox-check.mjs`. It runs `pwd` from the image, so that command must be installed.

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

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

try {
  const result = await sandbox.runCommand("pwd");
  console.log(await result.stdout());
} finally {
  await sandbox.stop();
}
```

Run `node --env-file=.env.local sandbox-check.mjs` to print the starting directory and stop the sandbox. This uses Sandbox compute, and `persistent: false` prevents an automatic snapshot for the check.

The sandbox uses your image's filesystem and tools. Start processes with `sandbox.runCommand()` because `ENTRYPOINT` and `CMD` do not run. Commands start in the Dockerfile's `WORKDIR`, or `/` when no `WORKDIR` is set.

## Limits and best practices

Keep these limits in mind when planning your images.

### Size limits

| Limit                 | Maximum | Notes                                                  |
| --------------------- | ------- | ------------------------------------------------------ |
| Compressed layer size | 2 GB    | Per layer                                              |
| Total image size      | 15 GB   | Calculated from compressed layers plus the config blob |
| Manifest body         | 4 MB    | —                                                      |
| Image config blob     | 1 MB    | —                                                      |

### Compatibility

- Compression: VCR accepts gzip or zstd compression only. Uncompressed OCI layers are rejected.
  
- Formats: OCI image manifests, OCI image indexes, Docker schema 2 image manifests, and Docker manifest lists
  
- Single-platform manifests must declare `os` and `architecture` in the image config
  
- Vercel Sandbox requires a `linux/amd64` manifest to boot the image
  

### Plan limits and pricing

| Limit                    | Hobby | Pro    | Enterprise |
| ------------------------ | ----- | ------ | ---------- |
| Repositories per project | 10    | 1,000  | 5,000      |
| Images per repository    | 50    | 10,000 | 50,000     |
| Tags per repository      | 1,000 | 10,000 | 50,000     |

Storage costs [$0.10 per GB across all plans](https://vercel.com/docs/container-registry/limits-and-pricing).

Additional practices to keep in mind:

- Use zstd compression when building images for VCR, as shown in step 4.
  
- Give each production build a unique tag, such as its commit SHA, and never reuse that tag. Use the image digest when you need to pin the exact image contents; reserve `latest` for local iteration.
  
- Push from your Vercel build environment when possible; it's authenticated for the current project automatically.
  

## Resources and next steps

- [Vercel Container Registry documentation](https://vercel.com/docs/container-registry)
  
- [Container Registry limits and pricing](https://vercel.com/docs/container-registry/limits-and-pricing)
  
- [Running container images on Vercel Functions](https://vercel.com/docs/functions/container-images)
  
- [Using custom images with Vercel Sandbox](https://vercel.com/docs/sandbox/concepts/images)
  
- [Introducing VCR: Vercel Container Registry (changelog)](https://vercel.com/changelog/introducing-vcr-vercel-container-registry)

## 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.
- [Running Docker on Vercel](https://vercel.com/kb/guide/docker): Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox.

## More Vercel Container Registry guides

- [How to choose between Functions, containers, and Daemons on Vercel](/kb/guide/vercel-functions-containers-daemons): Choose Vercel Functions for HTTP requests, container images for custom runtimes, and Daemons for continuous background workers.
- [How to 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.
- [How to migrate from Fly.io to Vercel](/kb/guide/migrate-fly-io-to-vercel): Move an app from Fly.io to Vercel. Map configuration, choose Functions or Daemons, plan persistent storage, and verify the production cutover.