Do ARM64 Runners Support Docker Buildx?

Yes. Buildx runs on ARM64 GitHub Actions runners and builds linux/arm64 natively, and an ARM64 job can attach a remote Docker builder just as an x64 job does.

Yes. Docker Buildx runs on ARM64 GitHub Actions runners, so docker buildx build --platform linux/arm64 on a label such as warp-ubuntu-latest-arm64-4x produces arm64 layers on aarch64 hardware with no emulation in the path (cloud runners documentation, checked on 2026-08-13). An ARM64 job can also attach a remote Docker builder exactly as an x64 job does, because the builder is reached over a TLS endpoint and the runner architecture never constrains which builder the job drives (Docker builders documentation).

Answer

Buildx is a CLI plugin that talks to a builder. Two things decide whether it works on an ARM64 runner: whether the plugin binary exists for aarch64, and whether the builder it points at can produce the platform you asked for.

The plugin exists. The Ubuntu 24.04 ARM64 runner images are compatible with GitHub's Ubuntu 24.04 ARM64 runners, and the package list for those images is published at actions/partner-runner-images, including Docker and the Buildx plugin. Ubuntu 26.04 ARM64 tracks actions/runner-images. docker/setup-buildx-action also publishes a linux/arm64 release, so a pinned setup step behaves the same on both architectures.

The builder side has two shapes. The default docker driver on the runner itself builds linux/arm64 natively, since the host is already aarch64. The remote driver points buildx at a builder virtual machine over tcp://, and WarpBuild's docker-configure action performs that docker buildx create --driver remote handshake for you inside the job (Docker builders documentation).

Attaching the remote builder from an ARM64 job is one action and a profile name:

name: build-arm64-image

on:
  push:
    branches: [main]

jobs:
  image:
    runs-on: warp-ubuntu-latest-arm64-4x
    steps:
      - uses: actions/checkout@v4

      - name: Confirm the runner architecture
        run: uname -m

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push on a remote builder
        uses: Warpbuilds/build-push-action@v6
        with:
          context: .
          push: true
          platforms: linux/arm64
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
          profile-name: "arm64-builder"

uname -m prints aarch64. Warpbuilds/build-push-action is a drop-in replacement for docker/build-push-action that sets up the remote builder itself, so the docker/setup-buildx-action step comes out when it was only there to create a builder (Docker builders documentation). On WarpBuild runners the API key is not required; off them, pass api-key: ${{ secrets.WARPBUILD_API_KEY }}.

WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners, and pricing is purely usage based. Per-minute rates are on the pricing page.

Detail

The local builder on an ARM64 runner

With no remote builder attached, the build runs on the runner. Ten ARM64 labels are available across Ubuntu 24.04 and Ubuntu 26.04, from 2 vCPU at $0.003 per minute to 32 vCPU at $0.048 per minute, each with 150GB SSD of ephemeral storage (Linux ARM64 runner catalog, checked on 2026-08-13). The build, the layer cache, and the context all live inside that disk and disappear when the job ends, so cache continuity has to come from somewhere external:

jobs:
  image:
    runs-on: warp-ubuntu-latest-arm64-8x
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - name: Show the active builder
        run: docker buildx inspect --bootstrap

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/arm64
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
          cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:arm64-buildcache
          cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:arm64-buildcache,mode=max

docker buildx inspect --bootstrap prints the driver and the platforms the builder advertises, which is the fastest way to confirm what a failing job is actually pointed at. On a remote builder, cache-from and cache-to are not required, because the builder disk holds the layer cache across jobs (Docker builders documentation).

One caveat is specific to ARM64 runners: the arm64 images for Ubuntu 24.04 set the work dir to /runner/_work, which differs from GitHub's /home/runner/work/ for the same instance (cloud runners documentation). Any docker run -v /home/runner/work/... mount or hardcoded context path breaks there, so use ${{ github.workspace }} in YAML and $GITHUB_WORKSPACE in shell steps.

Builder profile rates, and the arithmetic that picks a route

Remote Docker builder profiles bill per session, measured from when the builder action starts until the job completes, and jobs sharing a profile share one session. Every rate below comes from the Docker builders documentation, checked on 2026-08-13.

Profile sizeDiskPer minuteArchitectures
16 vCPU, 32GB100GB$0.06amd64, arm64, multi
32 vCPU, 64GB200GB$0.12amd64, arm64, multi
64 vCPU, 128GB200GB$0.24amd64, arm64, multi
96 vCPU, 192GB600GB$0.36amd64 only
96 vCPU, 192GB2TB$0.52amd64 only
192 vCPU, 384GB600GB$0.72amd64 only
192 vCPU, 384GB2TB$0.88amd64 only

arm64 and multi-arch profiles stop at 64 vCPU. The 96 vCPU and 192 vCPU sizes are amd64 only, so an arm64 profile tops out at the $0.24 row.

The runner keeps billing while the remote build runs, so the two rates add up. A job on warp-ubuntu-latest-arm64-8x at $0.012 per minute driving the 16 vCPU profile at $0.06 per minute costs $0.072 for every minute the build is in flight, against $0.012 per minute when the same build runs on the runner itself. For one job in isolation, the remote build has to finish inside a sixth of the local wall clock time before the pair costs less.

Two structural facts move that arithmetic, and both are why teams with heavy Dockerfiles pick the remote route anyway:

  1. Session billing across concurrent jobs. Ten jobs that overlap on one profile produce one session, not ten. Eight minutes of overlap on the 16 vCPU profile is $0.48 of builder time for the whole fan-out, so the per-job builder cost falls as concurrency rises.
  2. The cache and the disk are persistent. The builder disk carries the layer cache between jobs and between pull requests, and it runs from 100GB to 2TB against the runner's 150GB SSD. A profile that goes unused for 10 days has its cache reset automatically, and concurrent builds see an eventually consistent cache, so a layer written by one in-flight build may only be visible to the next one (Docker builders documentation).

Builder size is chosen independently of runner size, so a 2 vCPU ARM64 runner can drive a 64 vCPU arm64 profile. The runner and the builder are separate resources and both appear on the bill. The remote Docker builder catalog lists every profile size with its rate.

Where the arm64 architecture setting bites

The most common failure is exec format error during an arm64 or multi-platform build, and the cause is a profile without arm64 enabled (Docker builders documentation). Enable both architectures on the profile before a job sets platforms: linux/amd64,linux/arm64. A multi-architecture build runs each architecture on a separate builder instance, so it opens one session per architecture and each session bills independently. The multi-platform builder answer covers that split.

Is Docker Buildx preinstalled on ARM64 runners?

Yes. The Ubuntu 24.04 ARM64 images are compatible with GitHub's Ubuntu 24.04 ARM64 runners, and the published package list at actions/partner-runner-images includes Docker and the Buildx CLI plugin. docker/setup-buildx-action installs a pinned linux/arm64 release when you want a specific version. Sizes and labels are in the Linux ARM64 runner catalog.

Does attaching a remote builder change what the ARM64 job needs?

The job needs the builder profile name, plus api-key when it runs off WarpBuild runners. The build executes on the builder virtual machine, so the runner size stops driving build time, and the profile must have arm64 enabled before the job sets platforms: linux/arm64 (Docker builders documentation).

Why does an arm64 build fail with exec format error?

The builder profile is missing the arm64 architecture, so the build lands on an amd64 builder instance. Enable arm64 on the profile and rerun. The same setting governs multi-architecture builds, covered in the multi-platform builder answer.

Do I pay for the ARM64 runner and the builder at the same time?

Yes. They are two separate resources on two lines. The runner bills per minute at its label rate, and the builder bills per session from the first job start to the last job completion on that profile, so overlapping jobs on one profile share one billable stretch (remote Docker builder catalog).

Pick an ARM64 label from the Linux ARM64 runner catalog, size the builder profile from the remote Docker builder catalog, and price both against your own build minutes on the pricing page.

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.