GitHub Actions Matrix Builds en Reusable Workflows
Hoe matrix strategies en reusable workflows in GitHub Actions je CI/CD onderhoudbaar houden naarmate projecten groeien.
Jean-Pierre Broeders
Freelance DevOps Engineer
Matrix Builds en Reusable Workflows in GitHub Actions
Een pipeline die werkt voor één project is makkelijk. Maar wat als er tien repositories zijn die allemaal net iets anders gebouwd moeten worden? Of een library die op Node 18, 20 én 22 getest moet worden? Dan wordt copy-paste al snel een nachtmerrie.
GitHub Actions heeft twee features die dit oplossen: matrix strategies en reusable workflows. Samen houden ze pipelines DRY zonder dat de leesbaarheid eronder lijdt.
Matrix Strategy: Eén Job, Meerdere Configuraties
Een matrix strategy draait dezelfde job met verschillende combinaties van variabelen. Simpel voorbeeld voor een Node.js project:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Dit genereert zes jobs (3 versies × 2 OS'en). Elke combinatie draait parallel, dus de totale doorlooptijd blijft laag.
Specifieke Combinaties Uitsluiten
Niet elke combinatie is altijd relevant. Stel dat Windows + Node 18 niet ondersteund wordt:
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
exclude:
- node-version: 18
os: windows-latest
Of juist extra combinaties toevoegen met include:
strategy:
matrix:
node-version: [18, 20, 22]
include:
- node-version: 22
experimental: true
fail-fast: false
Die fail-fast: false is trouwens belangrijk. Standaard annuleert GitHub Actions alle matrix jobs zodra er één faalt. Voor testing wil je meestal álle resultaten zien, niet alleen de eerste fout.
Reusable Workflows: Eén Definitie, Overal Gebruiken
Matrix builds helpen binnen een repo. Maar wat als vijf repositories dezelfde deploy-stappen nodig hebben? Dan komen reusable workflows van pas.
Een reusable workflow is een gewoon workflow-bestand dat workflow_call als trigger heeft:
# .github/workflows/deploy-template.yml
name: Deploy Template
on:
workflow_call:
inputs:
environment:
required: true
type: string
node-version:
required: false
type: string
default: '20'
secrets:
DEPLOY_TOKEN:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci && npm run build
- run: |
curl -X POST "https://api.deployment.example/deploy" \
-H "Authorization: Bearer ${{ secrets.DEPLOY_TOKEN }}" \
-d '{"env": "${{ inputs.environment }}"}'
Aanroepen vanuit een andere workflow (of een andere repo):
jobs:
deploy-staging:
uses: my-org/shared-workflows/.github/workflows/deploy-template.yml@main
with:
environment: staging
secrets:
DEPLOY_TOKEN: ${{ secrets.STAGING_TOKEN }}
deploy-production:
needs: deploy-staging
uses: my-org/shared-workflows/.github/workflows/deploy-template.yml@main
with:
environment: production
secrets:
DEPLOY_TOKEN: ${{ secrets.PROD_TOKEN }}
Het mooie: wijzig de template op één plek en alle repositories profiteren ervan. Geen twintig PRs meer om een deploy-stap aan te passen.
Matrix + Reusable Workflows Combineren
De echte kracht zit in de combinatie. Een reusable workflow kan zelf ook een matrix bevatten:
# shared: test-and-deploy.yml
on:
workflow_call:
inputs:
node-versions:
type: string
default: '["18","20","22"]'
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ${{ fromJson(inputs.node-versions) }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci && npm test
De aanroepende workflow bepaalt welke versies getest worden. Elk project kan z'n eigen set meegeven zonder de template aan te passen.
Praktische Tips
| Situatie | Aanpak |
|---|---|
| Meerdere Node/Python/Java versies testen | Matrix strategy met versie-array |
| Zelfde pipeline in 5+ repos | Reusable workflow in shared repo |
| Staging → Production deployment | Reusable workflow met environment input |
| Lange matrix die veel kost | Gebruik fail-fast: true en max-parallel: 3 |
Een paar dingen die nog weleens misgaan:
- Secrets doorgeven vergeten. Reusable workflows erven niet automatisch secrets van de caller. Elke secret moet expliciet doorgegeven worden, of
secrets: inheritgebruikt worden (maar dat geeft alles door — niet altijd gewenst). - Versie pinnen. Verwijs naar reusable workflows met een SHA of tag, niet
@main. Anders kan een push op de shared repo onverwacht alle pipelines breken. - Matrix-limiet. GitHub staat maximaal 256 jobs per matrix toe. Klinkt veel, maar met drie dimensies zit je er sneller aan dan verwacht.
Wanneer Niet?
Voor een enkel project met één target-versie en een simpele deploy? Gewoon een normaal workflow-bestand. Reusable workflows en matrices voegen complexiteit toe die pas loont bij meerdere repos of configuraties. Begin simpel, refactor wanneer de duplicatie pijn doet.
