Can GitHub Actions Run on ARM64?

Yes. GitHub Actions runs natively on ARM64 runners. Point runs-on at an ARM64 label such as warp-ubuntu-latest-arm64-4x, billed at $0.006 per minute.

Last verified:

Yes. GitHub Actions runs jobs on ARM64 hardware natively, and the switch is a one line change to runs-on: point the job at an ARM64 runner label such as warp-ubuntu-latest-arm64-4x and the steps execute on an aarch64 machine with no translation layer in between. WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners, and the Linux ARM64 line starts at $0.003 per minute for the 2 vCPU size (WarpBuild cloud runners, checked on 2026-08-13).

Answer

There are three ways to get an ARM64 machine under a GitHub Actions job, and all three are native execution.

GitHub-hosted ARM64 runners. GitHub publishes ARM64 labels such as ubuntu-24.04-arm and bills them per minute on private repositories. The rates live in the GitHub Actions billing reference and on the GitHub pricing page.

Self-hosted ARM64 machines. The runner agent ships a linux-arm64 release on github.com/actions/runner, so any aarch64 box you own can register and advertise labels. You own the image, the scaling, and the patching. The GitHub Actions runner glossary entry covers how registration and label routing work.

Managed ARM64 runners. A provider registers ephemeral aarch64 virtual machines against your organization and you select them by label. WarpBuild runs this shape: the Linux ARM64 runner catalog lists ten labels across Ubuntu 24.04 and Ubuntu 26.04, from 2 vCPU to 32 vCPU.

The workflow change is the label and nothing else:

name: build-and-test

on:
  push:
    branches: [main]
  pull_request:

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

      - uses: actions/setup-go@v5
        with:
          go-version: "1.24"
          cache: true

      - name: Confirm the architecture
        run: |
          uname -m
          go env GOARCH

      - name: Build
        run: go build -o bin/api ./cmd/api

      - name: Test
        run: go test -race ./...

      - uses: actions/upload-artifact@v4
        with:
          name: api-linux-arm64
          path: bin/api

uname -m prints aarch64 and go env GOARCH prints arm64 on that runner. The rest of the workflow file is unchanged from the x86-64 version.

Emulation is the fallback for teams that cannot get an aarch64 machine. QEMU under docker/setup-qemu-action lets an x86-64 host produce an arm64 image by translating guest instructions in user mode. That path works for producing artifacts and it is a poor place to run a test suite, because every compile step, every dependency install, and every assertion pays translation overhead on top of the work itself.

Pricing on WarpBuild is purely usage based.

Detail

Native ARM64 and emulated ARM64 are different execution models

A native ARM64 job runs an aarch64 kernel and an aarch64 userspace. The compiler emits aarch64 instructions directly, the linker resolves aarch64 objects, and the test binary you assert against is the binary you ship to ARM64 production hosts. Architecture-specific behavior shows up where it belongs: CPU feature detection through /proc/cpuinfo, Neon and SVE code paths, memory ordering differences under a weaker memory model, and page size assumptions.

An emulated job runs an x86-64 kernel with binfmt handlers registered so aarch64 binaries get routed through QEMU user-mode emulation. Buildx uses this to produce linux/arm64 layers on an x86-64 builder. Three consequences matter when you plan a workflow:

  1. Every instruction in the guest binary is translated at run time, so the wall clock cost lands on compile-heavy and test-heavy steps.
  2. Runtimes that generate machine code at run time behave differently under translation. JIT-heavy language runtimes, Go builds that link cgo, and Rust builds with procedural macros that pull native dependencies are the usual sources of surprise.
  3. Host-level signals are wrong. Core counts, CPU flags, and hardware capability probes report the host, so any code that branches on them takes an untested path.

Cross-compilation is the third model and it sits between the two. You build aarch64 artifacts on an x86-64 host with a cross toolchain, which keeps the build fast, then run the test suite on a native ARM64 runner so assertions execute on real hardware. The multi-platform Docker build guide walks through the split.

The WarpBuild Linux ARM64 catalog

Ten labels, two Ubuntu releases, five sizes each. Every row comes from the cloud runners documentation, checked on 2026-08-13.

Runner labelOSvCPURAMStoragePer minuteAlias
warp-ubuntu-latest-arm64-2xUbuntu 24.0428 GB150GB SSD$0.003warp-ubuntu-2404-arm64-2x
warp-ubuntu-latest-arm64-4xUbuntu 24.04416 GB150GB SSD$0.006warp-ubuntu-2404-arm64-4x
warp-ubuntu-latest-arm64-8xUbuntu 24.04832 GB150GB SSD$0.012warp-ubuntu-2404-arm64-8x
warp-ubuntu-latest-arm64-16xUbuntu 24.041664 GB150GB SSD$0.024warp-ubuntu-2404-arm64-16x
warp-ubuntu-latest-arm64-32xUbuntu 24.0432128 GB150GB SSD$0.048warp-ubuntu-2404-arm64-32x
warp-ubuntu-2604-arm64-2xUbuntu 26.0428 GB150GB SSD$0.003none
warp-ubuntu-2604-arm64-4xUbuntu 26.04416 GB150GB SSD$0.006none
warp-ubuntu-2604-arm64-8xUbuntu 26.04832 GB150GB SSD$0.012none
warp-ubuntu-2604-arm64-16xUbuntu 26.041664 GB150GB SSD$0.024none
warp-ubuntu-2604-arm64-32xUbuntu 26.0432128 GB150GB SSD$0.048none

Storage is ephemeral and is deleted when the runner terminates, so anything you want to keep goes to an artifact, a cache, or a registry. The latest labels track Ubuntu 24.04 today, so pin warp-ubuntu-2404-arm64-4x or warp-ubuntu-2604-arm64-4x when you want the release to stay fixed across a rollout.

The ARM64 image caveats worth knowing before you switch

Four documented differences account for most of the failures teams hit on the first ARM64 run.

The work directory moves. 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 step with a hardcoded /home/runner/work/... path breaks. Use ${{ github.workspace }} in YAML and $GITHUB_WORKSPACE in shell steps, and check Docker -v mounts, coverage upload paths, and cache path globs for literals.

Ubuntu 22.04 on ARM64 is gone. The arm64 images for ubuntu-22.04 were deprecated on March 31, 2025 (cloud runners documentation). Those images were also thinner than their x86-64 siblings: they were based on the upstream ubuntu:22.04 image, the default user was root instead of runner, and tooling had to be installed with apt inside the workflow (preinstalled software documentation). Ubuntu 24.04 and 26.04 ARM64 removed both of those gaps.

Tooling parity starts at 24.04. The Ubuntu 24.04 ARM64 runners are compatible with GitHub's Ubuntu 24.04 ARM64 runners, and the package list is published at actions/partner-runner-images. Ubuntu 26.04 ARM64 tracks actions/runner-images. Read the list before you assume a language version is present; ARM64 images and x86-64 images do not always ship the same set.

Nested virtualization stays on x86-64. Workloads that need /dev/kvm, including Android emulator jobs, are not supported on ARM64 runners (cloud runners documentation). Those jobs go to an x86-64 runner with the nested-virtualization.enabled=true label.

Running x64 and ARM64 side by side

Most teams reach ARM64 through a matrix, because the point is proving the same test suite passes on both architectures before a release ships to aarch64 hosts.

name: matrix-test

on:
  pull_request:

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        include:
          - arch: amd64
            runner: warp-ubuntu-latest-x64-4x
          - arch: arm64
            runner: warp-ubuntu-latest-arm64-4x
    runs-on: ${{ matrix.runner }}
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - run: npm ci

      - run: npm test

      - name: Package for ${{ matrix.arch }}
        run: npm run build -- --target=${{ matrix.arch }}

      - uses: actions/upload-artifact@v4
        with:
          name: dist-${{ matrix.arch }}
          path: dist/

fail-fast: false keeps the x64 leg running when the ARM64 leg fails, which is what you want while you are working through architecture-specific breakage. Cache is enabled by default on Linux runners, including the ARM64 line, and cache keys are scoped per architecture by the setup actions, so the two legs do not fight over one entry.

Snapshot runners list Linux ARM64 among their supported platforms (snapshot runners documentation).

Multi-architecture Docker images

Two shapes work, and they price differently.

The native-runner shape runs one build job per architecture on a matching runner, pushes each image by digest, then merges them into one manifest list in a small final job. Every layer is built on real hardware for its target.

The remote builder shape keeps the workflow on one runner and sends the build to a dedicated builder virtual machine with a persistent layer cache. Builder profiles carry amd64, arm64, and multi-architecture options, and a multi-architecture build runs each architecture on a separate builder instance, producing one session per architecture (Docker builders documentation). Enable both architectures on the profile before you set platforms: linux/amd64,linux/arm64.

What ARM64 costs on GitHub Actions

Every WarpBuild rate below comes from the cloud runners documentation. Every GitHub rate comes from the GitHub Actions billing reference and the GitHub pricing page, checked on 2026-08-13.

WarpBuild ARM64 labelShapeWarpBuild per minuteGitHub-hosted ARM64 equivalentGitHub per minuteList price difference
warp-ubuntu-latest-arm64-2x2 vCPU, 8 GB$0.003ubuntu-24.04-arm$0.00540 percent lower list price
warp-ubuntu-latest-arm64-4x4 vCPU, 16 GB$0.0064-core Linux ARM64 larger runner$0.00825 percent lower list price
warp-ubuntu-latest-arm64-8x8 vCPU, 32 GB$0.0128-core Linux ARM64 larger runner$0.01414 percent lower list price
warp-ubuntu-latest-arm64-16x16 vCPU, 64 GB$0.02416-core Linux ARM64 larger runner$0.0268 percent lower list price
warp-ubuntu-latest-arm64-32x32 vCPU, 128 GB$0.04832-core Linux ARM64 larger runner$0.054 percent lower list price

The 2 vCPU row compares GitHub's private-repository rate, which is the rate paying teams run against.

Worked model: one service repository. A repository merges enough pull requests to queue 2,400 jobs a month, each running 6 minutes, on a 4 vCPU ARM64 runner. That is 14,400 minutes.

  • warp-ubuntu-latest-arm64-4x at $0.006 per minute: 14,400 x $0.006 = $86.40 per month.
  • GitHub 4-core Linux ARM64 larger runner at $0.008 per minute: 14,400 x $0.008 = $115.20 per month.
  • Difference: $28.80 per month, $345.60 over twelve months, which is 25 percent lower list price (GitHub pricing, checked 2026-08-13).
  • The same 14,400 minutes on warp-ubuntu-latest-x64-4x at $0.008 per minute is $115.20, so the architecture change is worth $28.80 a month on identical vCPU and RAM.

List price is one input to a fleet bill and build time is the other. Use your measured duration with the per-size rates on the pricing page rather than assuming a fixed saving from the architecture alone.

Worked model: multi-architecture image builds. A repository builds one multi-architecture image per pull request, 300 builds a month, 5 minutes of build time each.

  • Remote Docker builder route on the 16 vCPU, 32 GB, 100GB disk profile at $0.06 per minute per session, billed once per architecture: 300 x 5 x $0.06 x 2 sessions = $180.00 per month, with a persistent layer cache shared across the jobs on that profile.
  • Native runner route with two parallel jobs, one on warp-ubuntu-latest-x64-4x at $0.008 and one on warp-ubuntu-latest-arm64-4x at $0.006: 300 x 5 x ($0.008 + $0.006) = $21.00, plus a 1 minute manifest merge job on warp-ubuntu-latest-arm64-2x at $0.003, which adds $0.90, for $21.90 per month.

The two routes buy different things. The builder profile carries a persistent layer cache across every job that uses it, which is what dependency-heavy Dockerfiles want. The native runner route is cheaper per build and rebuilds layers unless you wire up registry cache or the Actions cache yourself.

Where ARM64 stops

ARM64 coverage in the catalog is Linux and macOS. The Windows catalog is x86-64 only, from warp-windows-latest-x64-4x through warp-windows-latest-x64-32x, so a Windows job stays on an x86-64 label (cloud runners documentation). The macOS runners are already ARM64, so a macOS job needs no architecture decision.

Inside Linux ARM64, the one hard limit is nested virtualization, which stays on the x86-64 line. Everything else in a normal workflow, including checkout, the language setup actions, caching, artifacts, service containers, and self-hosted registry pulls, behaves the same as it does on x86-64 once the work directory difference is handled.

Do I have to change my workflow to run a job on ARM64?

Only the runs-on line. Swap the label for an ARM64 label such as warp-ubuntu-latest-arm64-4x. Steps break only where they download an architecture-specific binary or pull a single-arch container image, so those URLs and tags need an aarch64 variant. The ARM64 migration guide lists the step types that need attention.

Does WarpBuild offer ARM64 runners for Windows?

No. The Windows catalog is x86-64 only. ARM64 runners cover Linux and macOS, so a Windows job stays on a warp-windows label. The Linux ARM64 runner catalog covers the aarch64 side.

Can I run Android emulator tests on ARM64 runners?

No. Nested virtualization and /dev/kvm access are not available on ARM64 runners. Send emulator jobs to an x86-64 runner with the nested-virtualization.enabled=true label, documented in the cloud runners reference.

Is Ubuntu 22.04 available on ARM64 runners?

No. The arm64 images for ubuntu-22.04 were deprecated on March 31, 2025. Use the Ubuntu 24.04 or Ubuntu 26.04 ARM64 labels, which track GitHub's ARM64 images, and check the package list linked from the preinstalled software documentation before you pin a language version.

Start on ARM64 with the labels in the Linux ARM64 runner catalog, price the change against your own job minutes on the pricing page, and build images for both architectures with the multi-platform Docker build guide.

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.