Skip to content
OpsAtlas

GitHub Actions matrix expander

CI/CD

Paste a workflow or a matrix block to see the exact list of jobs GitHub will run, which combinations exclude removes, and what include adds or creates.

Runs entirely in your browser — your input is never uploaded.

Paste a whole .github/workflows file or just the matrix block.

Paste a workflow or load the sample to see every job the matrix creates.

How GitHub expands a matrix

GitHub turns strategy.matrix into jobs in three steps:

  1. Product. Every key that holds a list is combined with every other: os: [a, b] × node: [20, 22] gives four jobs.
  2. Exclude. Each exclude entry removes every combination that matches all of its keys. An entry may list only some keys: - os: windows-latest removes every Windows job.
  3. Include. Each include entry is merged into every original combination whose original values it doesn’t contradict. If it contradicts all of them, it becomes a new job of its own.

Include is the step people get wrong. It never overwrites an original value, it can overwrite values added by an earlier include, and the new jobs it creates do not pick up keys from other include entries.

Example

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node: [20, 22]
    exclude:
      - os: windows-latest
        node: 20
    include:
      - node: 22
        lts: true
      - os: macos-latest
        node: 22

This produces four jobs:

Jobosnodelts
test (ubuntu-latest, 20)ubuntu-latest20
test (ubuntu-latest, 22, true)ubuntu-latest22true
test (windows-latest, 22, true)windows-latest22true
test (macos-latest, 22)macos-latest22

The first include adds lts: true to both existing node: 22 jobs. The second contradicts every original os value, so it becomes a new job. That new job does not get lts: true, because includes never apply to jobs created by other includes.

Tips for large matrices

  • Exclude broadly. One exclude entry with a single key can remove a whole row of the matrix.
  • Use include for one-off jobs. A coverage run or a nightly toolchain is cleaner as an include than as another matrix dimension.
  • Cap concurrency. max-parallel stops a 50-job matrix from using every runner in your organisation.
  • Turn off fail-fast for compatibility matrices. You usually want to see every failing platform, not just the first.
  • Keep names readable. Set name: test (${{ matrix.os }}, node ${{ matrix.node }}) on the job so the checks list stays scannable.

Frequently asked questions

In what order are exclude and include applied?
GitHub first builds the cartesian product of the matrix keys, then removes combinations matching any exclude entry, and only then processes include. An include can therefore re-add a combination you excluded, as a separate job.
Why did my include create a new job instead of adding a variable?
An include entry is merged into every original combination whose original values it does not contradict. If it contradicts all of them (for example a new os value), GitHub appends it as an extra job containing only the keys in that entry.
How many jobs can a matrix have?
A matrix can generate at most 256 jobs per workflow run. Larger matrices fail before any job starts, so the tool reports them as an error.
Can it expand matrices built with fromJSON?
No. Values like ${{ fromJSON(needs.setup.outputs.matrix) }} only exist while the workflow runs. Paste the JSON that the setup job outputs as a YAML matrix instead.
What do fail-fast and max-parallel change?
fail-fast (default true) cancels all in-progress and queued matrix jobs when one fails. max-parallel caps how many matrix jobs run at the same time; by default GitHub runs as many as runner availability allows.
  • YAML ⇄ JSON converter

    Convert YAML to JSON and back with exact error positions, anchor and merge-key expansion, and warnings for YAML 1.1 gotchas like the Norway problem.

    Kubernetes
  • Cron expression parser

    Translate a crontab schedule into plain English and list its next run times in UTC or your time zone, with warnings for common cron traps.

    Linux
  • docker run to Docker Compose converter

    Convert docker run commands into a clean compose.yaml: ports, volumes, env, networks, healthchecks and limits. Runs in your browser.

    Docker

Last updated · More CI/CD tools