Skip to main content

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 MachineProcessor (CPU)Memory (RAM)Storage (SSD)ArchitectureWorkflow labelPrice (USD/min)
Linux15 GB14 GBx64ubuntu-slim$0.002
Linux28 GB14 GBx64ubuntu-latest, ubuntu-24.04, ubuntu-22.04$0.006
Windows28 GB14 GBx64windows-latest, windows-2025, windows-2022$0.010
Linux28 GB14 GBarm64ubuntu-24.04-arm, ubuntu-22.04-arm$0.005
Windows28 GB14 GBarm64windows-11-arm$0.010
macOS414 GB14 GBIntelmacos-15-intel$0.062
macOS3 (M1)7 GB14 GBarm64macos-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 }}