Free — no signup required

Matrix Builds: Testing the Multiverse

2 min read

One Definition, Many Parallel Runs

Imagine you are building a Python library that must work on Python 3.10, 3.11, and 3.12, and on both Linux and macOS. Writing 6 separate jobs would be tedious to maintain — change one step and you have to update it in 6 places.

Matrix Strategies solve this by letting you define a set of variables. GitHub Actions generates a job for every combination of those variables and runs them all in parallel. A job's strategy.matrix might cross 2 operating systems with 3 Python versions, then use include to add one extra experimental combination not covered by the cross product (Ubuntu + an unreleased Python version), and exclude to remove one specific combination known to be incompatible (macOS + the oldest Python version). Inside the job, steps reference the matrix variables directly — setting up the matrix's Python version, and conditionally running a step only for one OS in the matrix.

How the math works: 2 OSes × 3 Python versions = 6 base jobs, minus 1 excluded combination, plus 1 include addition = 6 total parallel jobs.

fail-fast trade-off:
* fail-fast: true (the default): If any matrix job fails, GitHub immediately cancels all other in-progress matrix jobs. Good for saving compute minutes when you expect failures to be systemic.
* fail-fast: false: All matrix jobs run to completion regardless of individual failures. Good when you want a complete picture of which combinations are broken — especially useful when debugging cross-platform issues.

The include and exclude keys give you surgical control over the generated matrix. include adds jobs that would not otherwise exist (useful for experimental configurations). exclude removes specific combinations without rewriting the entire matrix.

Interview Tip

A common interview question is: "Your matrix build has 20 combinations and one flaky test is causing random failures. How do you handle this?" The answer involves two techniques: (1) set fail-fast: false so you get full visibility into which combinations are actually broken, and (2) use continue-on-error: ${{ matrix.experimental }} on the step level to allow experimental matrix entries to fail without failing the overall workflow. This shows you understand both the matrix mechanics and production reliability concerns.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free