GitHub Actions Cheatsheet

Matrix Builds

Use this GitHub Actions reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Basic Matrix

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [18, 20, 22]
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm test

Each matrix value becomes a separate job. Three node values = three parallel jobs.

Multi-Dimensional Matrix

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [18, 20]
    # 3 × 2 = 6 parallel jobs

Access in steps:

runs-on: ${{ matrix.os }}
steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}

Including Extra Combinations

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node: [18, 20]
    include:
      # Add extra key to an existing combo
      - os: ubuntu-latest
        node: 20
        experimental: true
      # Add a brand-new combo not in the base product
      - os: macos-latest
        node: 22
        experimental: true

Excluding Combinations

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [18, 20]
    exclude:
      - os: macos-latest
        node: 18     # skip this specific combo

fail-fast and max-parallel

strategy:
  fail-fast: false       # default: true — cancel remaining jobs on first failure
  max-parallel: 3        # run at most 3 matrix jobs at once (default: unlimited)
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [18, 20, 22]

Using Matrix Values in Expressions

steps:
  - name: Upload artifact
    uses: actions/upload-artifact@v4
    with:
      name: build-${{ matrix.os }}-node${{ matrix.node }}
      path: dist/

  - name: Set platform flag
    run: |
      if [ "${{ matrix.os }}" = "windows-latest" ]; then
        echo "EXT=.exe" >> $GITHUB_ENV
      else
        echo "EXT=" >> $GITHUB_ENV
      fi
    shell: bash

Dynamic Matrix (from JSON)

Generate the matrix at runtime from a prior job:

jobs:
  setup:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: |
          # Could be generated from a script, API call, or file
          echo 'matrix={"include":[{"env":"dev"},{"env":"staging"}]}' >> $GITHUB_OUTPUT

  deploy:
    needs: setup
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
    steps:
      - run: ./deploy.sh ${{ matrix.env }}

Matrix with Secrets / Env per Entry

strategy:
  matrix:
    include:
      - environment: staging
        url: https://staging.example.com
      - environment: production
        url: https://example.com

steps:
  - run: curl ${{ matrix.url }}/health

Cross-Platform Shell Scripts

# Avoid shell differences — use actions/github-script or explicit shell:
- name: Create dir
  shell: bash         # works on Windows too (Git Bash)
  run: mkdir -p dist

# Or branch on OS
- if: runner.os == 'Windows'
  run: New-Item -ItemType Directory -Path dist
  shell: pwsh
- if: runner.os != 'Windows'
  run: mkdir -p dist

Testing Against Multiple Language Versions

Node.js

strategy:
  matrix:
    node-version: ['18.x', '20.x', '22.x']
steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node-version }}

Python

strategy:
  matrix:
    python-version: ['3.10', '3.11', '3.12']
steps:
  - uses: actions/setup-python@v5
    with:
      python-version: ${{ matrix.python-version }}

Go

strategy:
  matrix:
    go-version: ['1.21', '1.22', '1.23']
steps:
  - uses: actions/setup-go@v5
    with:
      go-version: ${{ matrix.go-version }}

Referencing Matrix in Job Name

jobs:
  test:
    name: Test (${{ matrix.os }}, Node ${{ matrix.node }})
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        node: [18, 20]

Produces readable names in the Actions UI like "Test (ubuntu-latest, Node 20)".

Matrix Limits

LimitValue
Max matrix entries per workflow run256
Max include entries256
Combined (base × dims + include)256 total