Skip to content

Blog

Are there ARM64 runners for GitHub Actions in private repositories, and are they free?

·

Yes. Since 29 January 2026, GitHub’s standard ARM64 runners work in private repositories, and their minutes come out of your plan’s included usage, so they are free only until that is spent. A private repository gets 2 vCPUs, a public one 4. There is no ubuntu-latest-arm: you name the version, as in ubuntu-24.04-arm.

Plenty of guides still say the opposite, because until that date the labels worked in public repositories only. This post sets out what exists now, what a minute costs, what usually breaks on the move from x64, and when ARM64 should be a job of its own rather than an emulated step. Every GitHub fact was read from GitHub’s own pages on 10 November 2026 and is linked.

Which ARM64 runner labels exist, and why is there no ubuntu-latest-arm?

The labels are written into runs-on, and GitHub’s January 2026 changelog names three: ubuntu-24.04-arm, ubuntu-22.04-arm and windows-11-arm. GitHub’s runner documentation and its image list now carry two more.

LabelSystemWhere it is documented
ubuntu-24.04-armUbuntu 24.04Named in the January 2026 changelog
ubuntu-22.04-armUbuntu 22.04Named in the January 2026 changelog
windows-11-armWindows 11Named in the January 2026 changelog
ubuntu-26.04-armUbuntu 26.04Listed in GitHub's runner documentation and image list
windows-11-vs2026-armWindows 11, Visual Studio 2026Listed in GitHub's runner documentation

ubuntu-latest is an x64 label. GitHub has not added an ARM equivalent. In the discussion that announced the runners, a GitHub product manager replied on 22 January 2025 that there were no plans for a -latest label because “the latest tag causes confusion”; that was before ubuntu-26.04-arm was listed. A second request is marked as in GitHub’s backlog, and an open issue asks for ubuntu-arm-latest and windows-arm-latest; a maintainer there said they could not give a definitive answer. The label you have probably seen suggested, ubuntu-latest-arm, does not exist.

The practical effect is in a matrix. The x64 leg can follow ubuntu-latest to a newer Ubuntu while the ARM leg stays where you pinned it, so the two legs drift apart until somebody edits the file. Pin both legs to the same version on purpose:

jobs: test: strategy: matrix: runner: [ubuntu-24.04, ubuntu-24.04-arm] runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v7 - run: uname -m

The last step prints x86_64 on the first leg and aarch64 on the second, which is a cheap way to prove each leg is on the machine you meant.

Can private repositories use ARM64 runners now, and how are their minutes billed?

Yes, in every plan. GitHub launched the Linux ARM64 runners in January 2025 for public repositories only, and told people that the labels would fail in private ones. The changelog of 29 January 2026 lifted that. It says that because these are standard GitHub-hosted runners, “usage counts towards the free minutes included in your plan”.

Free minutes are a dollar amount, not a count. GitHub’s billing page gives $12 a month on Free, $18 on Pro and Team, and $300 on Enterprise Cloud, and its rates page lists the 2-core Linux ARM64 runner at $0.005 a minute and the Windows one at $0.010, each job rounded up to a whole minute. At the Linux rate that is, by simple division, 2,400 minutes for $12 and 3,600 for $18. Past the allowance, the same rate is charged. In a public repository, standard runners stay free. Our GitHub Actions pricing post walks through the allowances, the rounding and where a bill leaks.

What size are ARM64 runners in private vs public repositories?

Private repositories get half the machine. GitHub’s runner documentation lists the same figures for the Linux and the Windows ARM64 runners:

RepositoryvCPUMemoryStorage
Public repository416 GB14 GB
Private repository28 GB14 GB

If two vCPUs is too small for a private repository, the other route is a runner of a different size. On runners.io, ARM64 is sold under explicit labels on Ubuntu 24.04, 22.04 or 26.04 (swap the -2404- for -2204- or -2604-). The 2, 4, 8 and 16 vCPU labels are below. We ran one job on each of the 4, 8 and 16 vCPU labels on 10 November 2026 and read back 4, 8 and 16 CPUs and 15.6, 31.3 and 62.7 GiB of memory, on an aarch64 machine running Ubuntu 24.04. Each has a 75 GB disk; in those jobs the root filesystem read 71.6 GiB, of which about 62 GiB was free at the start of a job. A minute on ARM counts as 0.625 of a Linux x64 minute of the same size, and the 3,000 included run-minutes a month are drawn down at that rate.

LabelvCPUMemoryDisk
runnersio-2vcpu-ubuntu-2404-arm28 GB75 GB
runnersio-4vcpu-ubuntu-2404-arm416 GB75 GB
runnersio-8vcpu-ubuntu-2404-arm832 GB75 GB
runnersio-16vcpu-ubuntu-2404-arm1664 GB75 GB

What a minute costs on each size is on the pricing page. We do not sell Windows on ARM; windows-11-arm stays on GitHub. The labels page has every label and the -priority suffix, and the runners page has the rest of the range.

What usually breaks when a job moves from x64 to ARM64?

Anything that was built for x64 and is fetched at run time. GitHub’s documentation warns, in its limitations for arm64 macOS runners, that community actions “may not be compatible with arm64 and need to be manually installed at runtime”. The same is true on Linux ARM64, and GitHub’s ARM Ubuntu image says some tools do not support Arm and are left out. In practice the failures come in four groups.

Actions and tools that download an x64 binary. A JavaScript action runs on any architecture. A composite action or a script that downloads a release asset by a hard-coded name does not, and an action that runs a Docker image needs that image to have an ARM64 build. The usual message is exec format error. Read the action’s releases for an arm64 or aarch64 asset before you move.

Container images. A base image, a service container or a docker run target must publish an arm64 variant. Check with docker buildx imagetools inspect <image> and look for linux/arm64 in the list. Our image documentation puts it the same way: a container image needs an arm64 build.

Browsers. GitHub’s ARM Ubuntu image carries Firefox but leaves out Chrome and Edge. Our ARM64 image carries no browser at all; its documentation gives the reason as Chromium being published for x64 only. So browser and end-to-end tests are simplest on an x64 job here. Playwright lists arm64 Ubuntu among the systems its browsers support, so installing them in the job is an option, though we have not tried it on our image. On any provider, confirm that your browser vendor publishes a Linux ARM64 build before you move a browser job.

Caches and anything machine-specific. A cache of compiled output built on x64 is wrong on ARM64, so put the architecture in the key. The runner.arch context is X64 or ARM64:

- uses: actions/cache@v6 with: path: ~/.cargo/registry key: cargo-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Cargo.lock') }}

Two more limits are specific to our ARM64 jobs, so they are worth knowing if you are weighing the move: a sticky disk is not attached to them, and there is no /dev/kvm, so a hardware-accelerated emulator cannot run. The runner image page lists what is and is not installed.

When should ARM64 be a native job rather than an emulated QEMU step?

When the ARM64 part does real work: compiling, running a test suite, or a Docker build that takes more than a few seconds. Docker describes QEMU emulation as the easiest way to get started, with no Dockerfile changes, and also says it can be “much slower than native builds”, especially for compilation and compression. It recommends multiple native nodes or cross-compilation instead where possible. We have not measured the gap, so we give no multiple here.

Emulation is fine to prove an image builds for a second platform. This is the whole of it:

jobs: image: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v7 - uses: docker/setup-qemu-action@v4 - uses: docker/setup-buildx-action@v4 - uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64,linux/arm64 push: false

Native is the better choice for tests, because they then run your code on a real ARM64 processor rather than an emulated one, and for any build you wait on. Run the job on an ARM64 runner of its own, which is the matrix above, and join per-platform image builds afterwards. The full push-by-digest workflow is in our Docker build cache post. To put the ARM leg on our runners, change one line:

jobs: test: strategy: matrix: runner: [ubuntu-24.04, runnersio-2vcpu-ubuntu-2404-arm] runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v7 - run: uname -m

We have run jobs on runnersio-2vcpu-ubuntu-2404-arm, but not this exact workflow, so treat it as a sketch; the uname -m step is there to prove each leg on yours.

The ARM64 runners page has the start-up time we measure and date, and says what the job gets: a virtual machine of its own, native ARM64 with no emulation. Queued time is not billed, and a card is required to use the included minutes. A small test job on -2vcpu- is a cheap way to find out which of the four breakages above your repository has.

Run your CI and your infrastructure on one bill

Connect GitHub

Card required. You pay only for the minutes your jobs run.