Remote Docker Builders for GitHub Actions

A remote Docker builder runs docker build on a dedicated VM with a persistent layer cache outside the GitHub Actions runner. When to use one, when to skip it, and how it works.

Last verified:

A remote Docker builder runs docker build on a dedicated machine outside the GitHub Actions runner, with a layer cache that stays on that machine's local disk between jobs. Use one when your image builds lose their cache with the runner, are limited by the runner's CPU, or build a second architecture. Skip it when the image build is a small part of the job. WarpBuild remote Docker builders are created as a builder profile in the dashboard and selected from a workflow with one profile-name input on Warpbuilds/build-push-action.

The full setup with before and after workflows is on Docker Builds on GitHub Actions: Remote Builders. Sizes and prices are on Remote Docker Builders: Sizes and Pricing.

When is a remote Docker builder the right answer?

A remote builder helps when the image build is limited by runner CPU, by a cache that dies with the runner, or by emulation of a second architecture. It changes where the image build happens and where its cache lives, and it does nothing for the rest of your workflow, so check which of these your job logs show.

Image builds limited by runner CPU

When docker build runs inside the job, the build gets whatever vCPU the runner has, and it shares the runner with the rest of the job. BuildKit builds independent stages in parallel, so a Dockerfile with several independent stages can use more cores than a small runner has.

The usual fix is to move the whole job to a bigger runner. That works, but it charges the bigger rate for every minute of the job, including the steps that do not need the extra cores.

A builder profile separates the two. The size of the Docker machine is not related to the size of the GitHub Actions runner, because the builder profile you select decides it. The job keeps a small runner for checkout, tests, and the push, and the image build runs on a machine sized for image builds.

Layer cache lost with an ephemeral runner

Cloud runner storage is ephemeral and is deleted when the runner terminates. Any layer cache built during a job disappears with the machine unless the job exports it somewhere.

That is what cache-to: type=gha does. It serializes the layers and uploads them to a cache backend, and the next run downloads and imports them before the build starts. The export and import are real work in the job, and they grow with image size.

A builder profile keeps its cache on the builder's own disk. The next build reuses the layers in place with no export and no import step.

Multi-architecture builds

Building linux/arm64 on an x64 runner usually means QEMU. QEMU emulates the other architecture, and Docker's multi-platform build docs say this "can be much slower than native builds, especially for compute-heavy tasks like compilation".

Builder profiles support multi-architecture builds for amd64 and arm64, and each architecture runs on its own builder instance. The profile must have both architectures enabled in the dashboard. A profile with only amd64 enabled fails an arm64 build with exec format error.

If you would rather split the matrix across x64 and arm64 runners, run a job per architecture on warp-ubuntu-latest-x64-4x and warp-ubuntu-latest-arm64-4x, then merge the manifests. Multi Platform Docker Images on Native Runners walks through both shapes, and Native ARM64 Runners for GitHub Actions lists the ARM64 labels.

When to skip a remote builder

In two cases, a remote builder adds a session cost and gives little back. The first is jobs where the image build is a small share of the job time, such as a long test suite followed by a short build of a thin runtime image. The second is images whose build time is mostly the push to a registry rather than the layers themselves.

How does the builder lifecycle work during a job?

The action uses the Docker builders API to request a builder for your profile, connect buildx to it over TLS, run the build there, and close the session when the job ends.

  1. Assignment. The action asks for a builder assignment for the profile name. On WarpBuild runners it uses the runner's own credentials. Elsewhere it uses the api-key input.
  2. Ready check. The action waits until the builder reports ready. The timeout input sets how long it waits, in milliseconds, and the default is 10 minutes.
  3. Connection. The builder returns its host address plus a CA certificate, a client certificate, and a client key. The action creates a buildx instance with the remote driver pointed at that host over TLS.
  4. Build. BuildKit runs on the builder and reads cached layers from the builder's disk.
  5. Session end. The post step completes the builder session. You are billed until the session is completed, which is why the action closes it for you.

The cache belongs to the profile, not the job. A profile runs on one builder VM, and extra builders that share its cache can start under high concurrency. The cache is shared across builds on the profile but is eventually consistent, so layers written by one build may not be visible to another build running at the same moment. They become visible to later builds after synchronization. The builder cache has a TTL of 10 days, and a profile that goes unused for more than 10 days is reset automatically. You can also reset a profile's cache through the API when it holds a bad layer.

Builders also have a built-in timeout so that you are not charged for idle builders. If you use Warpbuilds/docker-configure@v1 for custom build commands, call it right before the step that runs the build.

How do you set up a remote Docker builder?

Setup takes four steps:

  1. Create a builder profile on the Docker Builders page.
  2. Swap docker/build-push-action for Warpbuilds/build-push-action and add profile-name.
  3. Remove docker/setup-buildx-action if it only creates a builder.
  4. Remove cache-from and cache-to.

Docker Builds on GitHub Actions: Remote Builders has the full before and after workflow, the GitHub-hosted runner variant with api-key, and the multi-architecture setup. Warpbuilds/bake-action@v7 is the matching replacement for docker/bake-action.

Docker builds run from Linux runners. macOS runners do not support nested virtualization and cannot run Docker.

How much does a remote Docker builder cost?

You pay for two things: the runner per minute, and the builder per session at the profile's per-minute rate. A session runs from when the builder action starts until the job completes, and concurrent jobs on one profile share one session. A multi-architecture build opens one session per architecture. Plan for roughly 8 vCPU and 16GB memory per concurrent build job on a profile.

Per-minute rates for every profile size and a worked billing example are on Remote Docker Builders: Sizes and Pricing. The Docker builders tab on the Spend page shows the cost of each builder session with its profile and architecture.

FAQ

Do I pay for both the GitHub Actions runner and the Docker builder?

Yes. The runner and the builder are two separate resources and both are billed. The runner is billed per minute at its catalog rate and the builder is billed per session, measured from when the builder action starts until the job completes.

How many concurrent builds fit on one builder profile?

There is no limit on the number of builds that can run concurrently on a builder profile. The recommended minimum is roughly 8 vCPU and 16GB memory per build job. WarpBuild Docker builders also support scaling out under high concurrency. Extra builders can start and share the profile's cache, and you keep the same action and profile name.

Do I still need cache-from and cache-to with a remote builder?

No. With WarpBuild Docker builders the cache-to and cache-from options are not required. A cached builder keeps the layers on its own disk and reuses them for later builds. The builder cache has a TTL of 10 days and resets if the profile goes unused for longer.

Can I use a remote Docker builder from a GitHub-hosted runner?

Yes. Builders work with both WarpBuild runners and other runners, including GitHub-hosted ones. On a GitHub-hosted runner, pass an API key through the api-key input so the action can request a builder.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.