How Much Disk Space Do GitHub Actions Runners Have?
WarpBuild runners carry 150GB SSD on every Linux x64 and ARM64 label, 256GB SSD on Windows labels, and 120GB or 270GB on macOS. Builder profiles reach 2TB.
Last verified:
Answer
WarpBuild runners carry 150GB SSD on every Linux x64 and Linux ARM64 label, 256GB SSD on every Windows label, and either 120GB or 270GB SSD on macOS depending on the size you pick. Runner storage is ephemeral working space and is deleted when the runner terminates, so anything you need after the job goes to a cache, an artifact, or a registry.
Every disk figure below comes from the cloud runners documentation, checked on 2026-08-13.
| Platform | Labels | Disk per runner | Per minute |
|---|---|---|---|
| Linux x64 | warp-ubuntu-latest-x64-2x through 32x, plus the 2204, 2404, and 2604 label sets | 150GB SSD | $0.004 to $0.064 |
| Linux ARM64 | warp-ubuntu-latest-arm64-2x through 32x, plus the 2604 label set | 150GB SSD | $0.003 to $0.048 |
| macOS, 6 vCPU | warp-macos-26-arm64-6x, warp-macos-15-arm64-6x, warp-macos-14-arm64-6x | 120GB SSD | $0.08 |
| macOS, 12 vCPU | warp-macos-26-arm64-12x, warp-macos-15-arm64-12x | 270GB SSD | $0.16 |
| Windows | warp-windows-latest-x64-4x through 32x, plus the 2025 and vs2026 label sets | 256GB SSD | $0.016 to $0.128 |
Two things in that table surprise people. Disk does not scale with vCPU on Linux or Windows: the 2 vCPU Ubuntu label and the 32 vCPU Ubuntu label both mount 150GB, and every Windows label mounts 256GB whether it has 4 vCPU or 32. On macOS the disk does move with the size, so warp-macos-26-arm64-12x carries 270GB against 120GB on the 6 vCPU labels.
Workloads that need more than the runner volume have two routes. Remote Docker builders run the image build on a dedicated builder virtual machine whose profiles start at 100GB of disk and go up to 2TB, with a persistent layer cache attached to the profile. BYOC runners on instance types that ship local NVMe SSDs get those disks detected, formatted, and mounted to the runner work directory at boot with no configuration, on Linux images (local SSD documentation).
Per-minute rates for every label above are on the pricing page.
Detail
Disk is working space and it disappears with the runner
Runner storage is deleted when the runner is terminated (cloud runners documentation). That is the design of an ephemeral runner: each job gets a clean machine, and nothing a job writes to the filesystem survives to the next one.
The practical consequence is that the volume size answers one question only, which is how much a single job can hold at its peak. It says nothing about how much a repository can accumulate over time. Anything with a lifetime longer than the job belongs in one of three places:
- Build caches, restored at the start of a job and saved at the end.
- Workflow artifacts, uploaded with
actions/upload-artifactand downloaded by later jobs. - A container registry or object store, for images and large binaries.
Snapshot runners are the exception worth knowing about. They capture a runner virtual machine mid-workflow so later jobs boot from that captured state rather than from a bare image, which moves a slow warm-up out of the critical path. Snapshots are deleted after 15 days (snapshot runners documentation).
An example disk budget for one job
The volume size is the size of the disk, and the runner image already occupies part of it with preinstalled tooling. Budget against measured free space instead of against the headline number. Here is a worked example for one image-building job on a Linux label with 150GB SSD, using example workload sizes you would replace with your own:
| What lands on disk | Example size |
|---|---|
Checkout with full history (fetch-depth: 0) | 12 GB |
| Base images pulled during the build | 8 GB |
| Built image layers across three tags | 15 GB |
| Dependency tree and compiled output | 6 GB |
| Test fixtures and database dumps | 4 GB |
| Artifacts staged for upload | 5 GB |
| Total peak | 50 GB |
At 50 GB of peak usage against a 150GB volume, that job has room. The failure mode teams hit is different: a matrix leg that pulls a fresh set of base images per iteration, or a build that keeps every intermediate tag, grows the third row without bound while the other rows stay flat. Docker layer growth is the usual reason a job that passed for months starts failing with a no-space error.
Checking free space from inside the workflow
Measuring beats guessing. This workflow records disk before and after the build, reclaims space between the build and test stages, and runs on a real WarpBuild label:
name: image-build
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: warp-ubuntu-latest-x64-16x
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Record disk before the build
run: |
df -h /
docker system df
- name: Build the image
run: docker build -t app:${{ github.sha }} .
- name: Reclaim space before the test stage
run: |
docker image prune -af --filter "until=1h"
docker builder prune -af
df -h /
- name: Integration tests
run: ./scripts/integration-test.sh
- uses: actions/upload-artifact@v4
with:
name: build-logs
path: logs/df -h / prints the free space on the volume the work directory sits on. docker system df breaks the Docker footprint into images, containers, local volumes, and build cache, which tells you which of the four is growing. Both commands cost a second and turn a mystery failure into a number you can act on.
When image layers are the problem, move the build off the runner
Remote Docker builders send the build to a dedicated builder virtual machine with a persistent layer cache, so image layers stop competing with the checkout for runner disk. Builder profiles are billed per session, and multiple concurrent jobs on the same profile share one session (Docker builders documentation, checked on 2026-08-13).
| Builder profile | Disk | Per minute | Architectures |
|---|---|---|---|
| 16 vCPU, 32GB RAM | 100GB | $0.06 | amd64, arm64, multi |
| 32 vCPU, 64GB RAM | 200GB | $0.12 | amd64, arm64, multi |
| 64 vCPU, 128GB RAM | 200GB | $0.24 | amd64, arm64, multi |
| 96 vCPU, 192GB RAM | 600GB | $0.36 | amd64 only |
| 96 vCPU, 192GB RAM | 2TB | $0.52 | amd64 only |
| 192 vCPU, 384GB RAM | 600GB | $0.72 | amd64 only |
| 192 vCPU, 384GB RAM | 2TB | $0.88 | amd64 only |
The arm64 and multi-architecture profiles top out at 64 vCPU, so the 2TB profiles are amd64 only.
Worked model: 500 image builds a month. Take a repository that builds one image per pull request, 500 builds a month, with a 4 minute builder session each. That is 2,000 session minutes, and the profile you pick sets the bill:
- 16 vCPU, 100GB disk at $0.06 per minute: 2,000 x $0.06 = $120.00 per month.
- 32 vCPU, 200GB disk at $0.12 per minute: 2,000 x $0.12 = $240.00 per month.
- 96 vCPU, 2TB disk at $0.52 per minute: 2,000 x $0.52 = $1,040.00 per month.
The runner that orchestrates the build bills separately. At 5 minutes per job on warp-ubuntu-latest-x64-4x at $0.008 per minute, 500 jobs add 2,500 minutes and $20.00. Cache storage, if the same team keeps 50 GB of cache entries, adds $10.00 a month at $0.20 per GB-month. All rates from the pricing page, checked on 2026-08-13.
Pick the profile by the disk and RAM the build actually needs. A Dockerfile with a large dependency layer and a handful of tags fits the 100GB profile; a monorepo producing dozens of images per run with a deep layer cache is what the 600GB and 2TB profiles exist for.
BYOC instances with local NVMe SSDs
On BYOC, the disk comes from the instance type you choose in your own cloud account. When that instance type ships local NVMe SSDs, the runner detects every local NVMe device at boot, stripes multiple devices into a RAID-0 array, formats it, and mounts it to the runner work directory before any job starts. No configuration is required (local SSD documentation).
Three constraints go with it. Auto-mount is available on Linux images only, so Windows and macOS runners use their regular volumes. Local SSDs are tied to the instance lifecycle, so the data is gone when the runner terminates, which matches how ephemeral runners already behave. RAID-0 gives throughput and capacity with no redundancy, which is the correct trade for build workspace.
The documentation names instance families rather than capacities, because capacity follows the instance type you select: c5d, m5d, r5d, i3, c6id, m6id, and r6id families on AWS, the -lssd machine types on GCP such as c3-standard-88-lssd, and VM sizes with local NVMe temp storage on Azure such as the Lsv3 and Lasv3 families. Check the capacity of the specific instance type in your cloud provider's own documentation before you size the runner set. The hosted versus BYOC comparison covers the rest of the trade.
What to change when a job runs out of disk
In rough order of effort:
- Add
df -h /anddocker system dfsteps, then read them. Half of these failures are one runaway directory. - Prune Docker between stages with
docker image prune -afanddocker builder prune -af. - Narrow the checkout.
fetch-depth: 1and sparse checkout cut the largest fixed cost on a big repository, which the large repository guide covers step by step. - Move image builds to a remote Docker builder profile so layers live on the builder rather than the runner volume.
- On BYOC, choose an instance type with local NVMe SSDs and let the auto-mount handle the rest.
The Action Debugger opens a shell on a paused runner so you can inspect its filesystem directly.
Related Questions
How much disk does a large repository need on a GitHub Actions runner?
A full-history checkout plus dependencies and build output usually fits inside the 150GB SSD on a Linux label, but measure it. Run df -h at the start of the job and again after the build, then size the workload against the number you see rather than against the volume size. The large repository guide covers checkout depth, sparse checkout, and cache layout for repositories where this gets tight.
Does the runner disk limit how much build cache I can keep?
No. Cache lives off the runner and is billed separately at $0.20 per GB-month plus $0.0001 per write or restore, so a 50 GB cache costs $10.00 a month (pricing page, checked on 2026-08-13). Only the restored copy of a cache entry occupies runner disk during the job, so a large cache costs money rather than runner space.
What do I do when Docker layers fill the runner disk?
Prune between steps with docker image prune -af, or move the build to a remote Docker builder profile. Builder profiles run from 100GB of disk on the 16 vCPU size up to 2TB on the 96 and 192 vCPU sizes, with a persistent layer cache that lives on the builder instead of the runner. The Docker builder catalog lists every profile.
Does the runner keep its disk between jobs?
No. Runner storage is deleted when the runner terminates. Snapshot runners capture a runner virtual machine mid-workflow so later jobs boot from that state, billed at $0.04 per restore and $0.025 per snapshot-hour, and snapshots are deleted after 15 days.
Size a job against the real numbers: the Linux x64 runner catalog lists the labels and their 150GB volumes, and the pricing page prices the runner, the builder profile, and the cache side by side.
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.