GitHub Actions Tutorial β€” Fail-Fast & Parallel

2 minute read

Fail-Fast & Parallel

By default, matrix jobs run in parallel and GitHub cancels all remaining jobs if any single job fails. You can control both behaviors.


Fail-Fast (Default: true)

When fail-fast is true (the default), one failing job cancels all other running matrix jobs:


strategy:
  fail-fast: true              # default
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [18, 20, 22]
runs-on: ${{ matrix.os }}
steps:
  - run: npm test

Job 1 (ubuntu/18)   βœ… success
Job 2 (ubuntu/20)   ❌ fails β†’ triggers cancellation
Job 3 (ubuntu/22)   🚫 cancelled
Job 4 (windows/18)  🚫 cancelled
Job 5 (windows/20)  🚫 cancelled
...remaining jobs    🚫 cancelled

Disable Fail-Fast

Set fail-fast: false to let all jobs complete regardless of failures:


strategy:
  fail-fast: false
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [18, 20, 22]
runs-on: ${{ matrix.os }}
steps:
  - run: npm test

Job 1 (ubuntu/18)   βœ… success
Job 2 (ubuntu/20)   ❌ failure
Job 3 (ubuntu/22)   βœ… success     ← still runs
Job 4 (windows/18)  βœ… success     ← still runs
Job 5 (windows/20)  ❌ failure
...all jobs run to completion

Use fail-fast: false when:

  • You want to see which combinations fail (cross-platform testing)
  • Failures are expected in experimental combinations
  • You need complete test results for reporting

Max-Parallel

Limit the number of jobs running simultaneously:


strategy:
  max-parallel: 3
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [18, 20, 22]
runs-on: ${{ matrix.os }}

Batch 1: Job 1, Job 2, Job 3    (run in parallel)
Batch 2: Job 4, Job 5, Job 6    (start after batch 1 finishes)
Batch 3: Job 7, Job 8, Job 9    (start after batch 2 finishes)

Use max-parallel when:

  • Deploying to shared environments (avoid conflicts)
  • Rate-limited external APIs
  • Conserving runner minutes on expensive runners (macOS)

Combining Fail-Fast and Max-Parallel


strategy:
  fail-fast: false
  max-parallel: 2
  matrix:
    environment: [dev, staging, production]
    region: [us-east-1, eu-west-1]
runs-on: ubuntu-latest
steps:
  - run: echo "Deploying to ${{ matrix.environment }} in ${{ matrix.region }}"

This deploys to 6 combinations, 2 at a time, without cancelling on failure.


Continue-on-Error for Matrix Jobs

Mark individual matrix combinations as allowed to fail:


strategy:
  fail-fast: false
  matrix:
    node: [18, 20, 22]
    include:
      - node: 22
        experimental: true
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental || false }}
steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}
  - run: npm test

If Node 22 fails, the overall workflow still shows as passing because continue-on-error is true for that combination.


Common Mistakes

Mistake Fix
All jobs cancel when one fails Set fail-fast: false
Too many parallel jobs hit rate limit Use max-parallel: N
Experimental build fails the workflow Use continue-on-error with include
max-parallel: 1 is very slow Only use serial execution when required

Quick Reference

Option Default Purpose
fail-fast true Cancel remaining on first failure
max-parallel Unlimited Limit concurrent jobs
continue-on-error false Allow individual job failure

← Previous: Include & Exclude

Next: Dynamic Matrix β†’

Updated: