Fail Fast
Fail-fast is the matrix strategy setting that cancels the remaining matrix jobs when one leg fails. What it defaults to, and when to switch it off.
Fail-fast is the matrix strategy setting that cancels the remaining jobs in a matrix as soon as one of its jobs fails. It lives under jobs.<job_id>.strategy in a workflow file, it defaults to true, and while it is on, the first failing combination ends the other combinations before they reach a conclusion.
The setting decides how much a single run tells you. Cancelling early stops spending machine time on combinations that may be about to fail for the same reason, while letting every leg finish produces the complete failure list from one run.
Definition
fail-fast is a boolean under a job's strategy key, alongside matrix and max-parallel. GitHub documents the default as true and describes the behavior as cancelling all in-progress and queued jobs in the matrix when any job in that matrix fails (GitHub workflow syntax, checked on 2026-08-13).
Three details narrow what the word covers.
The scope is one matrix. A workflow with three matrix jobs has three independent fail-fast decisions, and a failure in one job's matrix does not cancel the legs of another job's matrix. Jobs that list the failing job in needs are skipped for the usual dependency reason instead.
The conclusion is cancelled rather than failure. A leg that was cancelled midway reports no test result, so the run view shows one red leg and several grey ones, and the grey ones are unknown rather than passing.
The trigger is a failed job, so the setting interacts with continue-on-error. A leg marked continue-on-error: true that fails does not fail the workflow run, which is the documented way to carry an experimental combination inside a matrix that otherwise stops on failure.
| Key | Where it sits | What it decides |
|---|---|---|
strategy.fail-fast | Under jobs.<job_id>.strategy | Whether the first failing leg cancels the rest of the matrix. Default true. |
strategy.max-parallel | Under jobs.<job_id>.strategy | How many legs of the matrix run at the same time. |
jobs.<job_id>.continue-on-error | On the job | Whether a failing job marks the workflow run as failed. |
steps[*].continue-on-error | On a step | Whether a failing step marks its job as failed. |
A matrix can expand to at most 256 jobs per workflow run, so the number of legs a single failure can cancel is bounded by that limit (GitHub Actions limits, checked on 2026-08-13).
What each setting costs
With fail-fast on its default, a run stops at the first failure and the minutes already spent on the cancelled legs are still spent. If two combinations are broken, the second one appears only after the first is fixed, so the debugging loop is one run per failure.
With fail-fast: false, every combination runs to completion and bills its own minutes, and one run produces the whole failure list. The trade is machine time against the number of round trips it takes to see the true state of the matrix.
Example
This workflow tests six combinations, three operating systems against two Node versions, with fail-fast: false so that every combination reports.
name: test
on:
pull_request:
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [20, 22]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test -- --reporter=junit --outputFile=reports/junit.xml
- uses: actions/upload-artifact@v4
if: always()
with:
name: junit-${{ matrix.os }}-node${{ matrix.node }}
path: reports/Two lines in that file exist because of the setting. fail-fast: false keeps the five healthy legs running when one breaks. if: always() on the upload step keeps the report from a leg that was cancelled or failed, since a step guarded only by the default success condition is skipped the moment the job stops being successful. The artifact name includes both matrix values because actions/upload-artifact@v4 rejects two uploads under the same name in one run, and a matrix would otherwise send six uploads to one name.
Now take a run where the Windows leg on Node 20 fails two minutes in and the macOS leg on Node 22 fails at four minutes, while the other four legs need six minutes each to pass.
| Leg | With the default fail-fast: true | With fail-fast: false |
|---|---|---|
ubuntu-latest, Node 20 | Cancelled at 2 minutes, result unknown | Passes at 6 minutes |
ubuntu-latest, Node 22 | Cancelled at 2 minutes, result unknown | Passes at 6 minutes |
macos-latest, Node 20 | Cancelled at 2 minutes, result unknown | Passes at 6 minutes |
macos-latest, Node 22 | Cancelled at 2 minutes, result unknown | Fails at 4 minutes, report uploaded |
windows-latest, Node 20 | Fails at 2 minutes, report uploaded | Fails at 2 minutes, report uploaded |
windows-latest, Node 22 | Cancelled at 2 minutes, result unknown | Passes at 6 minutes |
| Total job minutes | 12 | 30 |
| Failures visible after one run | 1 of 2 | 2 of 2 |
The default run is cheaper by 18 job minutes and leaves one of the two real failures undiscovered. A developer fixes the Windows failure, pushes, and meets the macOS failure on the next run, so the wall clock cost of the second setting is measured against an extra full pipeline round trip rather than against zero.
That trade shifts with what the matrix is for. A matrix that exists to prove one artifact builds everywhere can stop at the first failure, because the artifact is already unshippable. A matrix that shards a test suite has legs that fail for unrelated reasons, and cancelling the siblings throws away results the run had already produced.
Related Terms
- Build matrix and how combinations expand: what the
matrixkey generates, howincludeandexcludereshape the set, and where the 256 job ceiling applies. - Building and tuning a GitHub Actions matrix: configuring a matrix end to end, including
max-parallel, artifact naming, and merging results from the legs. - Flaky tests and why one leg fails on unchanged code: the failure mode that makes a default
fail-fastmatrix cancel five healthy legs on the strength of one unreliable one. - WarpBuild cloud runner catalog: the operating systems and sizes available for each
osvalue a matrix expands. - WarpBuild reports documentation: per job duration, queue time, and billed time for each leg of a matrix, with CSV export.
- WarpBuild pricing: per minute rates by runner type.
FAQ
What is fail-fast in a GitHub Actions matrix?
It is the key under a job's strategy block that decides what happens to the rest of a matrix when one combination fails. With fail-fast set to true, the default, GitHub cancels every in-progress and queued job in that matrix as soon as the first one fails. With it set to false, each combination runs to its own conclusion and the run reports all of them.
Does fail-fast default to true or false?
True. A matrix with no fail-fast key behaves as if fail-fast were set to true, so the first failing combination cancels its siblings. Writing fail-fast false is the only way to keep every leg running.
When should a matrix set fail-fast to false?
When the value of the run is the full list of failures rather than the earliest one. Cross platform matrices, version compatibility matrices, and sharded test suites all fit, because a single leg cancelling the others hides how many combinations are broken and forces one run per fix.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.