GitHub Actions: CI/CD Workflows From First Run to Secure Deployments · GitHub Actions Workflows: Triggers, CI and Matrices
Build Matrices: Many Versions and Operating Systems
Run the same job across several runtimes and operating systems with strategy.matrix, include, exclude and fail-fast.
What you'll build
A test job that runs on three Python versions and two operating systems, with one combination excluded and one extra added.
The idea
A library should work on every version it claims to support. Instead of copying a job for each, use a matrix: GitHub creates one job per combination of the values you list, and each run reads its values from the matrix context.
matrix: { os: [...], python: [...] }produces every combination (here 2 x 3 = 6 jobs).excluderemoves combinations;includeadds extra ones or extra variables.fail-fast(defaulttrue) cancels the remaining jobs when one fails. Set it tofalseto see every failure.max-parallellimits how many jobs run at once.runs-on: ${{ matrix.os }}lets the matrix choose the operating system.
The code
name: Test matrix
on: [push, pull_request]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python: ["3.11", "3.12", "3.13"]
exclude:
- os: windows-latest
python: "3.11"
include:
- os: ubuntu-latest
python: "3.14"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
cache: pip
- run: python --version
Output
actionlint: no problems found
workflow: Test matrix
triggers: push, pull_request
jobs, in the order they run:
test: runs on ${{ matrix.os }} | matrix of 7 runs | 3 step(s)Run this on your computer — see “Get Started” for setup.
The summary above shows how many runs the matrix expands to: six combinations, one removed, one added.
Common mistakes
- Unquoted versions. In YAML
3.10is the number3.1. Always quote versions:"3.10". - Leaving
fail-fast: truewhen debugging. One failure cancels the others, hiding whether they fail too. - A huge matrix. Each combination consumes minutes; test the extremes (oldest and newest) rather than every version.
- Required checks and matrices. Required checks are per job name, which includes the matrix values; changing the matrix renames the checks.
Key points
strategy.matrixcreates a job per combination; read values via${{ matrix.<name> }}.includeandexcludeadjust the combinations.- Quote version numbers and consider
fail-fast: false. Further reading: GitHub Docs.
Practice questions
Why must `python: [3.10]` be written as `["3.10"]`?
Answer
YAML parses an unquoted 3.10 as the number 3.1, so the job would request Python 3.1. Quoting keeps it as the string "3.10".
What does `fail-fast: false` change?
Answer
By default a failing matrix job cancels the still-running ones. With fail-fast false, every combination runs to completion so you see all failures.
Open in the app to mark lessons complete, take notes and track your progress.