GitHub Actions runners are surprisingly stateful, and you’re not just getting more CPU/RAM when you upgrade; you’re getting a whole new machine with its own disk and network identity.
Let’s see it in action. Imagine you’re building a Go project.
name: Go Build Example
on: [push]
jobs:
build:
runs-on: ubuntu-latest # This is the default, let's upgrade this
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Build
run: go build ./...
Now, let’s say your builds are taking too long because you’re hitting I/O bottlenecks or simply need more compute. The obvious solution is to upgrade the runner. GitHub offers larger runners, like ubuntu-22.04-amd64 (which is a bit of a misnomer, it’s just ubuntu-latest on a bigger machine) or even GPU runners. The key here is that runs-on doesn’t just select an OS; it selects a specific hardware instance from GitHub’s pool.
Here’s how you’d switch to a larger runner:
name: Go Build Example - Larger Runner
on: [push]
jobs:
build:
runs-on: ubuntu-22.04-amd64 # Switched to a larger runner
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Build
run: go build ./...
The ubuntu-22.04-amd64 runner typically offers more vCPUs and RAM than the default ubuntu-latest (which is usually ubuntu-20.04 or ubuntu-22.04 depending on GitHub’s current default). This means your Go compiler can run faster, and if your build process involves a lot of parallel compilation or disk-intensive operations like fetching dependencies, you’ll see a noticeable speedup.
The mental model for runners is that each job gets a fresh, ephemeral virtual machine. When you change runs-on, you’re not reconfiguring the existing VM; you’re requesting a different type of VM from GitHub’s fleet. This is why cache invalidation can be a concern: the next build might land on a different physical host entirely, even if it’s the same runner type.
The underlying infrastructure for these larger runners is still managed by GitHub, so you don’t need to worry about provisioning hardware. You’re essentially renting access to more powerful compute resources on demand. This is particularly useful for:
- Large Codebases: Compiling millions of lines of code can be CPU-bound.
- Complex Dependency Graphs: Fetching and installing numerous dependencies can be I/O and network bound.
- Resource-Intensive Tests: Running integration tests or end-to-end tests might require more memory or CPU.
- Container Builds: Building Docker images can be very I/O heavy.
The exact specifications for each runner type are documented by GitHub, but generally, larger runners offer more RAM (e.g., 32GB vs. 7GB) and more vCPUs (e.g., 8 vCPUs vs. 2 vCPUs). This direct increase in resources is the primary driver of faster build times.
What most people don’t realize is that the disk I/O on these runners is also significantly improved. While the default runners might use general-purpose SSDs, the larger runners often leverage higher-performance storage, which can dramatically speed up operations like cloning large repositories, installing packages, or writing build artifacts. This isn’t just about raw CPU power; it’s about the entire I/O subsystem being more capable.
The next step after optimizing your build performance with larger runners is to consider how to manage build artifacts and their storage, especially if you’re generating large outputs.