GitHub Actions Tutorial — Matrix Patterns
Matrix Patterns
Here are real-world matrix patterns you’ll use in production CI/CD pipelines.
Pattern 1 — Cross-Platform Library Testing
Test a Node.js library across all platforms and LTS versions:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test
9 parallel jobs cover every combination. fail-fast: false ensures you see all failures.
Pattern 2 — Python Version Grid with Coverage on One
Run tests on multiple Python versions, but only collect coverage on one:
jobs:
test:
strategy:
matrix:
python: ['3.10', '3.11', '3.12']
include:
- python: '3.12'
coverage: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- run: pip install -r requirements.txt
- name: Run tests
if: "!matrix.coverage"
run: pytest
- name: Run tests with coverage
if: matrix.coverage
run: pytest --cov=src --cov-report=xml
- name: Upload coverage
if: matrix.coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage.xml
Pattern 3 — Multi-Database Integration Tests
Test against multiple database backends:
jobs:
test:
strategy:
matrix:
database: [postgres, mysql, sqlite]
include:
- database: postgres
db-image: postgres:16
db-port: 5432
- database: mysql
db-image: mysql:8
db-port: 3306
- database: sqlite
db-image: ''
db-port: ''
runs-on: ubuntu-latest
services:
db:
image: ${{ matrix.db-image }}
ports:
- ${{ matrix.db-port }}:${{ matrix.db-port }}
env:
DATABASE_TYPE: ${{ matrix.database }}
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
Pattern 4 — Build Multi-Architecture Docker Images
jobs:
build:
strategy:
matrix:
platform:
- linux/amd64
- linux/arm64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
platforms: ${{ matrix.platform }}
tags: myapp:latest
Pattern 5 — Sequential Deployment with Matrix
Deploy to environments in order, one at a time:
jobs:
deploy:
strategy:
max-parallel: 1
matrix:
environment: [dev, staging, production]
runs-on: ubuntu-latest
environment: ${{ matrix.environment }}
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to ${{ matrix.environment }}..."
max-parallel: 1 forces sequential deployment: dev → staging → production.
Pattern 6 — Artifact Per Matrix Combination
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.os }}
path: ./dist
release:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: build-*
merge-multiple: true
path: ./all-builds
- run: ls -la ./all-builds
Common Mistakes
| Mistake | Fix |
|---|---|
| Artifact name collision in matrix | Include matrix values in artifact name |
| Services block with empty image | Use if: to conditionally skip service setup |
| Max-parallel doesn’t guarantee order | Order within max-parallel batches is not guaranteed |
| Matrix expands more than expected | Check cartesian product size before running |
Quick Reference
| Pattern | Use Case | Key Config |
|---|---|---|
| Cross-platform | Test on all OS | fail-fast: false |
| Version grid + flag | Coverage on one version | include: with extra var |
| Database matrix | Multi-DB testing | include: with service config |
| Multi-arch Docker | ARM + AMD64 | Platform as matrix variable |
| Sequential deploy | Ordered environments | max-parallel: 1 |
← Previous: Dynamic Matrix
Next: Practice Exercises →