Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~14 min· topic 4 of 4

Topic 1.4

Matrix Builds & Parallel Jobs

In one line

A matrix build runs the same job multiple times with different parameters — testing across several language versions or operating systems in parallel, instead of writing a nearly-duplicated job for each one.

0/4 · 0%

Think of it like this

Instead of writing a completely separate, nearly-identical set of instructions for testing a recipe with three different oven brands, you write the recipe ONCE and specify 'run this exact same recipe against each of these three ovens' — a MATRIX build is exactly this: one job definition, run automatically against every combination of a declared set of variables.

Key ideas

  1. 01

    A MATRIX BUILD declares one or more VARIABLES (a list of Java versions, a list of operating systems) and the CI platform automatically runs the SAME job once for every combination — testing against Java 17 AND 21, on both Ubuntu AND Windows, is a 2×2 matrix producing four genuinely separate, parallel job runs from one single job definition.

  2. 02

    This directly solves a genuinely common real problem: confirming a library or application actually works correctly across every version and platform it claims to support, WITHOUT hand-writing a separate, nearly duplicated job definition for each combination — one matrix definition scales automatically as combinations are added or removed.

  3. 03

    Matrix jobs run in PARALLEL by default (subject to the platform's own concurrency limits) — a 2×2 matrix's four jobs typically all start at roughly the same time, meaning the total wall-clock time is close to however long ONE combination takes, not four times that, a genuinely significant advantage over running the same checks sequentially.

  4. 04

    fail-fast (a matrix-level setting, defaulting to true on most platforms) controls whether ONE failing combination immediately CANCELS every other still-running combination in the matrix — genuinely useful to disable (fail-fast: false) when you specifically want to see the FULL picture of which combinations pass and which fail, rather than stopping at the first failure and leaving the rest unknown.

  5. 05

    PARALLEL JOBS more broadly (Phase 0.2 already introduced the concept) aren't limited to matrix builds — any genuinely independent jobs (three different kinds of tests, say) can run in parallel simply by NOT declaring a dependency between them (GitHub Actions' needs: keyword is what creates a genuine sequential dependency; omitting it lets jobs run concurrently by default).

Code & diagrams

MatrixExpansiondiagram

One job definition, automatically expanded into every combination, run in parallel.

Rendering diagram…
matrix-build.ymlmarkdown

One job definition, four parallel runs — testing real compatibility across versions and platforms.

jobs:
  test:
    strategy:
      fail-fast: false     # see the full picture, don't cancel the rest on one failure
      matrix:
        java-version: [17, 21]
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ matrix.java-version }}
          distribution: "temurin"
      - run: mvn test
parallel-independent-jobs.ymlmarkdown

Genuinely independent jobs, run in parallel simply by NOT declaring a dependency between them.

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps: [ ... ]

  lint:
    runs-on: ubuntu-latest
    steps: [ ... ]

  # No "needs:" here — both jobs above start at the same time, independently
  deploy:
    needs: [unit-tests, lint]   # this one genuinely waits for BOTH to succeed first
    runs-on: ubuntu-latest
    steps: [ ... ]

Explain it without notes

01

Why does a matrix build's total wall-clock time stay close to the duration of ONE combination, rather than growing with the total number of combinations?

02

Why might a team deliberately set fail-fast: false on a matrix build, even though it means a genuinely broken combination doesn't stop the others immediately?

Practice

01

Create a matrix build testing at least two different versions of something (a language version, if your build tool supports it easily) and confirm both combinations run as genuinely separate, parallel jobs in your CI platform's UI.

02

Toggle fail-fast between true and false on a matrix with a deliberately failing combination, and observe the difference in whether the other combinations continue running or get cancelled.

Trade-offs

  • ↔

    Matrix builds genuinely scale testing coverage with minimal added configuration, but every additional matrix dimension MULTIPLIES the total number of parallel jobs (and therefore total compute cost/capacity used) — a 3×3×2 matrix is already 18 separate job runs from one job definition, which is worth being deliberate about on a platform charging by runner-minutes or with limited concurrent-job capacity, rather than adding matrix dimensions purely because it's easy to do.

Done when you can

  • I can create a matrix build testing multiple combinations of a variable and confirm they run in parallel.

  • I understand the fail-fast setting and can reason about when disabling it is genuinely useful.

  • I understand that omitting needs: between jobs lets them run in parallel by default.