Depot CI

Build and use custom images

Build a reusable custom image from the Depot base image that includes your tools and dependencies.

How it works

A custom image in Depot CI is a snapshot of a sandbox environment. The snapshot is stored in your org's Depot registry (registry.depot.dev) and any job in any workflow can reference it by name.

To build the custom image create a job that runs only your setup steps on the Depot base image and include the snapshot keyword. After your setup steps complete, Depot captures the state of the sandbox environment and pushes it to the Depot registry as a reusable image. Any job can then use that snapshot as its starting image to skip the setup steps entirely.

Custom images can only be used in workflows running on Depot CI.

Quickstart

The first run will build the snapshot for you. Subsequent runs will reuse the snapshot and skip the setup job. Time is saved every time you run this workflow.

jobs:
  setup:
    runs-on: depot-ubuntu-latest
    snapshot: your-image:v1
    steps:
      - name: Install dependencies
        run: sudo apt-get update && sudo apt-get install -y your-tool-here

  work:
    needs: setup
    runs-on:
      image: your-image
    steps:
      - uses: actions/checkout@v4
      - run: your-tool-here do-the-thing

Build a custom image in a dedicated workflow

You can create a separate workflow for the build image job, and then use the resulting image in other workflows. Build a custom image using a job that runs on a standard Depot sandbox and installs the tools and dependencies you want to bake in. The job creates your custom image and pushes it to the Depot Registry. This pattern is efficient because you run the image build workflow once to create the image and then only when dependencies change.

To create the build image workflow:

  • Add snapshot to the job that installs your tools and dependencies.
  • Choose the custom image name and, optionally, a version tag.

Snapshot jobs are unique because they first check whether the requested image tags already exist. If the tags exist, Depot skips the job and reuses the existing snapshot. If the tags do not exist, Depot runs the job and creates the snapshot after the job completes.

Example build image job:

jobs:
  build-image:
    runs-on: depot-ubuntu-latest
    snapshot: ci-base:v1
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y your-tool-here

For advanced configuration, use the expanded snapshot form:

jobs:
  build-image:
    runs-on: depot-ubuntu-latest
    snapshot:
      image-name: ci-base
      version: v1
      with:
        max-age: 5d
    steps:
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y your-tool-here

The with block configures the underlying depot/snapshot-action. For example, max-age forces the snapshot to be rebuilt after the configured age. Snapshots include non-masked environment variables from the setup job; built-in sensitive token variables are excluded by default, and env-mask can blacklist additional variable names.

Use a custom image in a job

Any job in any workflow on Depot CI can specify your custom image. The custom image is in the Depot registry (registry.depot.dev). Images from external registries aren't supported.

To run a job on a custom image, specify runs-on with size and image keys (both required).

  • size: the size of the sandbox
  • image: the custom image name or Depot Registry URL defined by the snapshot job

The runs-on.image value must reference an image created by a snapshot job as described in Snapshot a sandbox to build a custom image. You can't use any other images or artifacts, even if they exist in the Depot registry. The image can either be a full Depot Registry reference {orgId}.registry.depot.dev/some-image or use shorthand names like ci-base, which Depot expands to {orgId}.registry.depot.dev/depot/snapshots/ci-base.

Example specifying a custom image in a job:

jobs:
  use-image:
    runs-on:
      size: 2x8
      image: ci-base
    steps:
      - uses: actions/checkout@v4
      - run: your-tool-here do-the-thing

Available values for size:

SizeCPUsMemory
2x828 GB
4x16416 GB
8x32832 GB
16x641664 GB
32x12832128 GB
64x25664256 GB

For sandbox information and pricing, see Depot CI sandboxes.

Versioning

If no explicit version is given, Depot uses the latest tag. If an explicit version like v1 is given, Depot tags the snapshot as both v1 and latest.

This lets consumers choose between pinning a version and following the latest snapshot. It also lets the producer version act as a cache buster: changing snapshot: ci-base:v1 to snapshot: ci-base:v1.1 creates a new version, while consumers that use image: ci-base will still automatically pick up the new latest tag.

Full example for Playwright

name: ci-test-e2e

on:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  setup-e2e:
    runs-on: depot-ubuntu-latest
    snapshot:
      image-name: e2e-base
      version: 1.0
      with:
        max-age: 3d
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4

      - name: Install test dependencies
        run: pnpm install --frozen-lockfile

      - name: Install Chromium
        run: pnpm exec playwright install --with-deps chromium

      - name: Preload service images
        run: docker pull postgres:16

  dashboard-e2e:
    needs: setup-e2e
    runs-on:
      image: e2e-base
      size: 2x8
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v4
        with:
          clean: false

      - name: Start app
        run: docker compose up -d --wait

      - name: Run Playwright
        env:
          APP_URL: http://127.0.0.1:3030
        run: pnpm exec playwright test --shard ${{ matrix.shard }}/4

Best practices

Set clean: false when pre-cloning a repository: If your custom image includes a pre-cloned copy of your repository, set clean: false on actions/checkout so it skips running git clean -ffdx before fetching. Without clean: false, checkout removes untracked files from the pre-cloned repo (like installed dependencies or build artifacts), negating the benefit of pre-cloning.

steps:
  - uses: actions/checkout@v4
    with:
      clean: false