Caching for Docker builds
Cache Docker layers on RunsOn runners with the Magic Cache (type=gha), the S3 BuildKit backend (type=s3), or the ephemeral ECR registry (type=registry).
RunsOn gives you three ways to cache Docker layers, all backed by storage inside your own AWS account. They trade off simplicity vs. speed — try each on your workload and pick the fastest:
| Backend | Buildx type | Notes |
|---|---|---|
| Magic Cache | type=gha | Transparent — reuses the standard GitHub cache backend, swapped to S3 behind the scenes. Simplest. |
| S3 BuildKit | type=s3 | Points Buildx directly at the RunsOn cache bucket. Durable and simple. |
| Ephemeral registry | type=registry | Registry-native (ECR). Often the fastest, and lets you share full images across jobs. |
Magic Cache (type=gha)
If you already enable the Magic Cache with extras=s3-cache, your type=gha Buildx exporter is transparently redirected to S3 — no extra configuration:
jobs: docker: runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache steps: - uses: runs-on/action@v2 - uses: actions/checkout@v6 - uses: docker/setup-buildx-action@v3 - uses: docker/build-push-action@v4 with: context: "." push: false tags: test cache-to: type=gha,mode=max cache-from: type=ghaS3 BuildKit backend (type=s3)
The same S3 cache bucket can be used directly with the type=s3 Buildx cache backend. In our tests it is faster than type=gha and slightly slower than the ephemeral registry.
Flex
Run on a cache-enabled runner and point Buildx at the RunsOn cache bucket:
jobs: docker: runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=s3-cache steps: - uses: actions/checkout@v6 - uses: docker/setup-buildx-action@v3 - uses: docker/build-push-action@v4 with: context: "." push: true tags: <your-tag> cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=maxFleet
For Fleet, enable S3 cache behavior in the runner fleet and use the same Buildx cache settings in workflow YAML:
runners = { linux-docker = { cpu = 8 ram = 16 family = ["c8i"] image = "ubuntu24-full-x64" extras = ["s3-cache"] }}Authentication is handled automatically: as long as the workflow runs on a RunsOn runner, Buildx uses the runner’s IAM role to access the S3 bucket. All RunsOn runners share that role, so layers are shared across repositories and workflows within a single organization. If you require stronger isolation, configure multiple RunsOn stacks and use environments to separate workflows.
Ephemeral registry (type=registry)
Since v2.8.2, RunsOn can automatically create an ephemeral registry (an ECR repository in your AWS account) to temporarily store images and layers shared across build jobs — no external registry to configure. In our tests, type=registry was slightly faster than both type=s3 and type=gha.
Flex
Enable the registry login helper with the ecr-cache extra, then use RUNS_ON_ECR_CACHE as your registry target:
jobs: ecr-cache: runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/extras=ecr-cache steps: - uses: actions/checkout@v6 - uses: docker/setup-buildx-action@v3 - uses: docker/build-push-action@v4 env: TAG: ${{ env.RUNS_ON_ECR_CACHE }}:my-app-latest with: context: . push: true tags: ${{ env.TAG }} cache-from: type=registry,ref=${{ env.TAG }} cache-to: type=registry,ref=${{ env.TAG }},mode=maxFleet
The ephemeral registry is not exposed by the Fleet module yet. Use Flex for workflows that depend on ecr-cache; see Fleet current limitations.
Use cases
The ephemeral registry can be used to:
- Push and pull images that need to be temporarily shared across workflow jobs. For instance, build an image in one job (e.g. for integration tests) and use it in one or many dependent jobs.
- Cache Docker layers across workflow jobs.
Accessing the ephemeral registry
Runners automatically get push/pull access to this registry through the EC2 instance profile. The RUNS_ON_ECR_CACHE environment variable contains the full registry URL (e.g. 123456789012.dkr.ecr.us-east-1.amazonaws.com/runs-on-ab12cd34-ephemeral-registry). The repository name is auto-generated per stack, so always reference ${{ env.RUNS_ON_ECR_CACHE }} rather than hardcoding a path. When you include ecr-cache in the extras label, the RunsOn agent logs into the registry before your job starts.
Cleanup and considerations
Images are automatically cleaned up after 10 days. The registry is shared across all runners launched by the same RunsOn stack, so only store images and layers that can be shared; create multiple environments if you need better isolation.
On the built-in v3 CloudFormation path, the embedded stack creates the free S3 gateway VPC endpoint but not EC2 or ECR interface VPC endpoints. If your runners use private networking and need private ECR access, add the relevant interface endpoints through Terraform / OpenTofu or your own networking stack.
Limitations
- All three Docker caching backends are only available on Linux runners.