Build a reusable custom image from the Depot base image that includes your tools and dependencies.
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.
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-thingYou 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:
snapshot to the job that installs your tools and dependencies.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-hereFor 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-hereThe 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.
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 sandboximage: the custom image name or Depot Registry URL defined by the snapshot jobThe 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-thingAvailable values for size:
| Size | CPUs | Memory |
|---|---|---|
2x8 | 2 | 8 GB |
4x16 | 4 | 16 GB |
8x32 | 8 | 32 GB |
16x64 | 16 | 64 GB |
32x128 | 32 | 128 GB |
64x256 | 64 | 256 GB |
For sandbox information and pricing, see Depot CI sandboxes.
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.
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 }}/4Set 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