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

5 maart 20266 min. leestijd

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

SituatieAanpak
Meerdere Node/Python/Java versies testenMatrix strategy met versie-array
Zelfde pipeline in 5+ reposReusable workflow in shared repo
Staging → Production deploymentReusable workflow met environment input
Lange matrix die veel kostGebruik 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: inherit gebruikt 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.

Wil je op de hoogte blijven?

Schrijf je in voor mijn nieuwsbrief of neem contact op voor freelance projecten.

Neem Contact Op