GPU runners for GitHub Actions: options, pricing and setup
Run GitHub Actions jobs on a GPU: GitHub's T4 runner and its limits, self-hosted GPU runners, and EC2 GPU runners with RunsOn, with prices and examples.
Standard GitHub-hosted runners have no GPU, so a job that trains a model, runs CUDA kernels, or tests a GPU code path needs a different runner. There are three ways to get one:
| Option | GPUs | Plans | Price per minute |
|---|---|---|---|
| GitHub GPU larger runner | 1× NVIDIA Tesla T4 (16 GB) | Team, Enterprise Cloud | $0.052 |
| Self-hosted runner on your own GPU machine | Whatever you own | Any | Your hardware |
| RunsOn on EC2, in your AWS account | T4, A10G, L4, L40S, V100, A100, H100, H200… | Any, including Free | From $0.0047 (T4, spot) |
GitHub’s GPU runner#
GitHub offers one GPU size as a larger runner: 4 vCPUs, 28 GB of RAM, 176 GB of SSD and one NVIDIA Tesla T4 with 16 GB of VRAM, on Ubuntu or Windows. To set it up, an organization admin creates a new GitHub-hosted runner, picks a GPU-optimized image (NVIDIA’s image from the Partner tab, with the drivers installed) and a size from the GPU-powered tab, then jobs target it by name:
jobs: cuda-tests: runs-on: linux-gpu-t4 # the name given to the runner steps: - uses: actions/checkout@v7 - run: nvidia-smi - run: make test-cudaWhat to know before choosing it:
- Team or Enterprise Cloud only, billed from the first minute (included minutes don’t apply).
- One GPU, one model. The T4 is a 2018 inference card: fine for CUDA unit tests and small models, slow for training anything sizeable, and there’s no multi-GPU size.
- At most 100 concurrent GPU jobs per organization or enterprise.
- Price: at $0.052 a minute, a 30-minute nightly job costs about $47 a month.
Self-hosted GPU runners#
Any machine with an NVIDIA GPU, the driver and the runner application can run GPU jobs. Register it with a label such as gpu and target runs-on: [self-hosted, linux, gpu]. Install the NVIDIA Container Toolkit too if jobs use containers (docker run --gpus all).
This is the cheapest route for a GPU workstation you already own. On cloud GPUs it’s often the most expensive one: a GPU instance left running between jobs costs dollars an hour while idle, so you need ephemeral runners that start per job and stop afterwards. Don’t attach a persistent GPU runner to a public repository.
GPU runners with RunsOn#
RunsOn starts an EC2 instance in your AWS account for each job and terminates it when the job ends, so you pay only for the minutes used, at AWS prices. Pick the GPU instance and a GPU image (NVIDIA driver, CUDA toolkit and container toolkit preinstalled) in the label:
jobs: cuda-tests: runs-on: runs-on=${{ github.run_id }}/family=g4dn.xlarge/image=ubuntu24-gpu-x64 steps: - uses: actions/checkout@v7 - run: nvidia-smi - run: make test-cudaTypical GPU runners, with their 7-day average spot price in us-east-1 (instance plus disk):
| Runner | Instance | Spot / min | On-demand / min |
|---|---|---|---|
| 4cpu·T4 | g4dn.xlarge | $0.0047 | $0.0091 |
| 8cpu·T4 | g4dn.2xlarge | $0.0049 | $0.013 |
| 16cpu·A10 | g5.4xlarge | $0.013 | $0.027 |
| 48cpu·4×T4 | g4dn.12xlarge | $0.023 | $0.066 |
Larger cards (L4 on g6, L40S on g6e, A100 and H100 on p4d and p5) work the same way, if your AWS account has the quota for them. GPU quotas start at zero in new accounts, so request them before the first job. See GPU runners in the docs for images, quotas and examples.
Running GPU tests without wasting GPU minutes#
A GPU minute costs several times a CPU minute, so keep the GPU job small:
on: pull_request: schedule: - cron: "0 3 * * *" # nightly full run
jobs: cpu-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - run: pytest -m "not gpu"
gpu-tests: needs: cpu-tests # don't pay for a GPU if the cheap tests fail if: github.event_name == 'schedule' || contains(github.event.pull_request.labels.*.name, 'gpu') runs-on: runs-on=${{ github.run_id }}/family=g4dn.xlarge/image=ubuntu24-gpu-x64 timeout-minutes: 60 steps: - uses: actions/checkout@v7 - run: nvidia-smi - run: pytest -m gpu- Run CPU tests first and the GPU job only after they pass (
needs). - Run the full GPU suite nightly, and on pull requests only when asked (a
gpulabel). - Set
timeout-minutesso a hung kernel doesn’t burn the default 6 hours. - Build and cache Docker images and model weights outside the GPU job: downloading a 10 GB model on every run costs GPU minutes. See caching.
- Check that the GPU is there before running anything expensive:
nvidia-smifails fast when the driver or the device is missing.