How to Choose and Configure GitHub Actions Runners (+Tips)
Types of GitHub Actions Runners
- The Workflow label on the right is the identifier used when configuring workflows
- Larger runners for large-scale jobs also exist but are omitted here due to their high cost
| Virtual Machine | Processor (CPU) | Memory (RAM) | Storage (SSD) | Architecture | Workflow label | Price (USD/min) |
|---|---|---|---|---|---|---|
| Linux | 1 | 5 GB | 14 GB | x64 | ubuntu-slim | $0.002 |
| Linux | 2 | 8 GB | 14 GB | x64 | ubuntu-latest, ubuntu-24.04, ubuntu-22.04 | $0.006 |
| Windows | 2 | 8 GB | 14 GB | x64 | windows-latest, windows-2025, windows-2022 | $0.010 |
| Linux | 2 | 8 GB | 14 GB | arm64 | ubuntu-24.04-arm, ubuntu-22.04-arm | $0.005 |
| Windows | 2 | 8 GB | 14 GB | arm64 | windows-11-arm | $0.010 |
| macOS | 4 | 14 GB | 14 GB | Intel | macos-15-intel | $0.062 |
| macOS | 3 (M1) | 7 GB | 14 GB | arm64 | macos-latest, macos-14, macos-15, macos-26 (public preview) | $0.062 |
Choosing the Right Runner
- ubuntu-slim: The lightest option; this is the only runner that runs in a container rather than a VM. Use it for simple jobs. Some tools may not be pre-installed, so setup time may be longer.
- ubuntu-latest: The latest stable Linux version, suitable for general-purpose jobs.
- arm64: Use when Arm64 architecture is required or when you want to reduce costs.
- x86: The default Linux runner; choose this when you have no specific requirements. Performance may vary depending on the VM assigned, so execution time can fluctuate.
- windows / macOS: Use when builds or tests on Windows or macOS are required. Choose these only when necessary, as they are more expensive.
How to Configure GitHub Actions Runners
Specify the runner in your workflow definition file as follows:
jobs:
a_job:
runs-on: ubuntu-latest # ← Specify the runner's Workflow label here
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Build project
run: echo "Building on Ubuntu latest"
Configuring Multiple Runners with Matrix Strategy
When you want to run the same job in parallel across multiple runners, use the matrix strategy.
This feature allows you to flexibly specify tests and builds across different OSes and environments based on conditions and combinations.
Basic Usage (Testing on Multiple OSes)
When you specify a single parameter in the matrix (OS in this example), the job runs for all values defined for that parameter. For example, the following configuration runs tests on three OSes: Ubuntu, Windows, and macOS.
jobs:
test:
runs-on: ${{ matrix.os }} # Use the OS specified in the matrix
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Run tests
run: echo "Testing on ${{ matrix.os }}"
Running All Combinations of OS x Node.js Versions
When you specify multiple parameters in the matrix, the job runs for all combinations. For example, the following configuration runs tests across 2 OSes (Ubuntu and Windows) and 3 Node.js versions (18, 20, and 22). This setup runs 2 OSes x 3 Node.js versions = 6 jobs in parallel.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 20, 22]
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Run tests
run: npm test
Excluding Specific Combinations
You can use exclude to remove unwanted combinations (in this example, macOS + Node.js 18).
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20, 22]
exclude:
- os: macos-latest
node-version: 18
steps:
- name: Run tests
run: npm test
Adding Specific Combinations
You can use include to add specific combinations to the matrix (in this example, Windows + Node.js 22).
You can also add custom parameters like experimental and use them within the job.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: [20]
include:
- os: windows-latest
node-version: 22
experimental: true
steps:
- name: Run tests
run: npm test
Practical Example: Cost Optimization
For example, you can run unit tests and integration tests on the lightweight ubuntu-slim, while running heavier E2E tests only on the full-spec ubuntu-latest:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-slim] # Run lightweight tests on ubuntu-slim
test-type: [unit, integration]
include:
- os: ubuntu-latest # Run E2E tests only on full-spec runner
test-type: e2e
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Run ${{ matrix.test-type }} tests
run: npm run test:${{ matrix.test-type }}