GitHub Actions Matrix-Build: Parallele Multi-Version-Tests in der Praxis
Letzte Woche ging unser Projekt live – und schon am Nachmittag kam das Feedback: Unter Node 16 zeigt die Seite nur noch einen weißen Bildschirm. In dem Moment wurde mir klar, dass etwas schiefgegangen war.
Zwei Stunden lang habe ich gesucht. Logs durchforstet, Code dreimal verglichen – und am Ende lag es an einer API, die JSON.stringify() unter Node 16 anders behandelt als unter Node 20: Die alte Version wirft bei zirkulären Referenzen sofort einen Fehler, die neue Version schluckt das still. Unsere CI-Pipeline testete nur Node 20 – dieses Kompatibilitätsproblem wurde nie abgefangen.
Beim Nachbesprechen dachte ich: Hätten wir Multi-Version-Tests parallel laufen lassen, wäre das vor dem Go-Live aufgefallen. Seitdem habe ich mich ernsthaft mit dem Matrix-Build in GitHub Actions beschäftigt. Der Begriff klingt technisch, bedeutet aber schlicht: Ein Job wird automatisch in mehrere Teile zerlegt, die gleichzeitig auf verschiedenen Versionen und Plattformen laufen.
In diesem Artikel gehe ich Matrix von den Grundlagen bis zu fortgeschrittenen Techniken durch: Basis-Syntax, exclude/include-Filter, fail-fast-Strategie und max-parallel-Ressourcensteuerung. Am Ende erhalten Sie eine vollständige Node.js-Multi-Version-Vorlage zum direkten Kopieren. Etwa 10 Minuten Lesezeit – danach können Sie Ihre CI auf parallele Multi-Version-Tests umstellen.
Matrix-Grundlagen – in 5 Minuten startklar
Matrix in einem Satz: Sie schreiben einen Job, GitHub Actions expandiert ihn automatisch zu mehreren parallelen Tasks.
Beispiel: Sie definieren drei Node.js-Versionen [18, 20, 22]. Matrix erzeugt drei unabhängige Test-Tasks – jeweils unter Node 18, Node 20 und Node 22. Alle starten gleichzeitig und laufen parallel, ohne sich gegenseitig zu stören.
Die Minimal-Konfiguration sieht so aus:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci && npm test
Der Schlüssel liegt bei strategy.matrix. node-version ist ein selbst definierter Variablenname; das Array [18, 20, 22] enthält die möglichen Werte. GitHub Actions iteriert über dieses Array, weist jedem Lauf einen Wert an matrix.node-version zu und erstellt eine entsprechende Job-Instanz.
Die Syntax ${{ matrix.node-version }} referenziert den aktuellen Wert – beim ersten Lauf 18, beim zweiten 20, beim dritten 22.
Als ich Matrix das erste Mal nutzte, fragte ich mich: Laufen die drei Tasks seriell oder parallel? Antwort: standardmäßig parallel. Bei einem Push startet GitHub drei Runner gleichzeitig. In der Praxis: Drei Versionen seriell zu testen dauerte 15 Minuten – mit Matrix nur noch 5 Minuten, weil die Laufzeit der langsamsten Task entscheidet.
Ein Hinweis: Parallelität verbraucht mehr Runner-Minuten. Drei Tasks bedeuten das Dreifache an Laufzeitkosten. Im Free-Tier (2.000 Minuten pro Monat) kann eine große Matrix das Kontingent schnell aufbrauchen. Dazu kommen wir später bei max-parallel.
exclude/include-Filter – die Test-Matrix fein steuern
Kombinieren Sie mehrere Dimensionen, wächst die Anzahl der Matrix-Kombinationen exponentiell.
Drei Node-Versionen [16, 18, 20] und drei Betriebssysteme [ubuntu, windows, macos] ergeben 3 × 3 = 9 Tasks. Fügen Sie Test-Suites [unit, integration, e2e] hinzu, sind es 27. Für Open-Source-Projekte mag das noch gehen – für kleine Teams sind Runner-Minuten echte Kosten.
Manche Kombinationen sind zudem sinnlos. Node 16 ist EOL (End of Life) – es unter Windows und macOS zu testen, ist reine Zeitverschwendung. Hier kommt exclude ins Spiel:
strategy:
matrix:
node-version: [16, 18, 20]
os: [ubuntu-latest, windows-latest, macos-latest]
exclude:
- node-version: 16
os: windows-latest
- node-version: 16
os: macos-latest
Bei exclude listen Sie die auszuschließenden Kombinationen auf. Die Konfiguration oben entfernt Node 16 + Windows und Node 16 + macOS. Aus 9 Tasks werden 7 – 22 % weniger Runner-Minuten.
include macht das Gegenteil: spezifische Kombinationen oder zusätzliche Variablen hinzufügen. Beispiel: Node 23 als experimentelle Version, aber nur auf Ubuntu:
strategy:
matrix:
node-version: [16, 18, 20]
os: [ubuntu-latest, windows-latest]
include:
- node-version: 23
os: ubuntu-latest
experimental: true
Ein Detail: include fügt nicht nur Kombinationen hinzu, sondern kann auch extra Variablen setzen. experimental: true existiert nur im Node-23-Task. In späteren Steps können Sie darauf reagieren – z. B. Fehler bei experimentellen Versionen den Workflow nicht abbrechen lassen:
- name: Run tests
run: npm test
continue-on-error: ${{ matrix.experimental == true }}
Eine Falle, in die ich getreten bin: die Priorität von exclude und include. GitHub Actions führt zuerst include aus (Kombinationen hinzufügen), dann exclude (entfernen). Wenn Sie eine Kombination per include hinzufügen und per exclude ausschließen, erscheint sie nicht. Die Reihenfolge ist entscheidend.
Kurz zusammengefasst:
exclude: unnötige Kombinationen entfernen – spart Geld und Zeitinclude: Sonderkombinationen ergänzen und zusätzliche Variablen für differenzierte Behandlung setzen
fail-fast und max-parallel – Parallelstrategie optimieren
Ein Standardverhalten, das leicht übersehen wird: fail-fast: true.
Bedeutung: Scheitert eine Task in der Matrix, bricht GitHub Actions sofort alle anderen noch laufenden Tasks ab. Bei 10 parallelen Tasks, die nach einer Minute scheitert die dritte – die restlichen 7 werden sofort beendet.
Ist das gut? Kommt auf das Szenario an.
Bei PR-Checks ist fail-fast sinnvoll. Jemand pusht Code, Node-18-Tests schlagen fehl – Sie müssen nicht warten, bis alle Versionen durch sind. Schnelles Feedback, weniger Ressourcen.
Bei Nightly-Tests oder regelmäßiger Regression ist fail-fast oft ungünstig. Sie wollen einen vollständigen Report: Welche Versionen scheitern, welche nicht? Fällt Node 18 durch und stoppt alles, wissen Sie nicht, ob Node 20 dasselbe Problem hat. Dann setzen Sie fail-fast: false.
strategy:
fail-fast: false
matrix:
node-version: [16, 18, 20]
max-parallel begrenzt, wie viele Tasks gleichzeitig laufen. Standardmäßig gibt es kein Limit – GitHub startet alle Tasks so schnell wie möglich. Bei großen Matrizen mit z. B. 30 Kombinationen wollen Sie vielleicht nicht alle Runner-Ressourcen auf einmal verbrauchen.
strategy:
fail-fast: true
max-parallel: 6
matrix:
node-version: [16, 18, 20, 22]
test-suite: [unit, integration, e2e]
Die Konfiguration oben erlaubt maximal 6 gleichzeitige Tasks. 30 Kombinationen laufen in Batches à 6. Vorteil: kontrollierbarer Ressourcenverbrauch. Nachteil: längere Gesamtlaufzeit.
Eine einfache Entscheidungstabelle:
| Szenario | fail-fast | max-parallel | Begründung |
|---|---|---|---|
| PR-Check | true | unbegrenzt | Schnelles Feedback – ein Fehler stoppt den Rest |
| Nightly-Test | false | 4–6 | Vollständiger Report, alle Bugs sichtbar |
| Große Matrix (>20 Kombinationen) | true | 4 | Ressourcen begrenzen, Kontingent schonen |
| Experimentversion | false | unbegrenzt | Fehler in Experimenten beeinflussen nicht die Gesamtbewertung |
In den meisten Fällen reicht das Standard-fail-fast: true. Nur wenn Sie eine vollständige Diagnose brauchen, setzen Sie es auf false. max-parallel spielt bei kleinen Matrizen (unter 10 Kombinationen) kaum eine Rolle – bei großen Matrizen sollten Sie es ernst nehmen.
Wichtig: max-parallel begrenzt nur, wie viele Tasks GitHub Actions gleichzeitig startet – nicht die Anzahl Ihrer Runner. Bei self-hosted Runnern kann ein zu niedriger Wert Warteschlangen erzeugen und alles verlangsamen. Bei öffentlichen Runnern ist die Einstellung sinnvoll.
Vollständige Vorlage – Node.js Multi-Version-Test-Pipeline
Die bisherigen Abschnitte waren Einzelbausteine. Hier eine vollständige, direkt kopierbare Konfiguration.
Die Vorlage enthält:
- Drei Node-Versionen (16, 18, 20)
- Zwei Test-Suites (unit und integration)
- Zwei Betriebssysteme (Ubuntu und Windows)
- Automatisches Caching für schnellere Abhängigkeitsinstallation
- Ausschluss von Node-16-Tests unter Windows (EOL-Version)
name: Multi-Version Test Matrix
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
max-parallel: 6
matrix:
node-version: [16, 18, 20]
test-suite: [unit, integration]
os: [ubuntu-latest, windows-latest]
exclude:
- node-version: 16
os: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ${{ matrix.test-suite }} tests
run: npm run test:${{ matrix.test-suite }}
Einige Highlights:
runs-on: ${{ matrix.os }}: Das Betriebssystem ist dynamisch – jede Task nutzt den passenden Runner gemäß Matrix-Kombination.
cache: 'npm': Eingebautes Caching in setup-node. Anhand des Hashs von package-lock.json werden npm-Abhängigkeiten gecacht und beim nächsten Lauf wiederverwendet. In der Praxis reduziert das die Installationszeit um über 50 %.
fail-fast: false: Bewusst auf false gesetzt – Ziel der Multi-Version-Tests ist es, alle Probleme zu finden. Scheitert eine Version, laufen die anderen weiter.
npm run test:${{ matrix.test-suite }}: Vorausgesetzt, in package.json existieren test:unit und test:integration – Matrix ruft beide nacheinander auf.
Wie viele Tasks entstehen?
3 Versionen × 2 Tests × 2 Betriebssysteme = 12 Tasks, minus ausgeschlossenes Node 16 + Windows (2 Test-Suites) = 10 Tasks.
Praxiswerte: Mit dieser Konfiguration sank die CI-Zeit in mehreren Projekten von 25 Minuten (seriell) auf etwa 8 Minuten – hauptsächlich durch Parallelität und Dependency-Caching.
Bei größeren Projekten mit mehr Kombinationen:
max-parallelerhöhen (z. B. 8 oder 10)- E2E-Tests in einen separaten Job auslagern, damit sie den Rest nicht ausbremsen
continue-on-errorfür experimentelle Versionen nutzen
Kopieren Sie die Vorlage nach .github/workflows/test.yml, passen Sie Versionen und Test-Suite-Namen an – dann sollte es laufen.
Fazit
Kurz die Kernpunkte:
Matrix expandiert einen Job automatisch zu mehreren parallelen Tasks. Die Konfiguration ist einfach, der Effekt direkt: Ein Push, drei Versionen parallel – die CI-Zeit entspricht der langsamsten Task.
exclude/include dienen der Feinsteuerung. Bei zu vielen Kombinationen spart exclude über 20 % Runner-Minuten. include ergänzt Sonderfälle und erlaubt zusätzliche Variablen.
fail-fast ist standardmäßig true – ein Fehler stoppt alle anderen Tasks. Für PR-Checks passt das; für Nightly-Tests setzen Sie es auf false. max-parallel begrenzt die Parallelität – relevant vor allem bei großen Matrizen.
Caching ist Standard. Eine Zeile cache: 'npm' in setup-node halbiert die Abhängigkeitsinstallation.
Nächster Schritt: Kopieren Sie die Vorlage nach .github/workflows/ und starten Sie mit Node.js-Drei-Version-Tests. Wenn das stabil läuft, erweitern Sie schrittweise auf mehr Plattformen und Test-Suites. Bei Fragen zum Caching lohnt der Artikel der Serie „GitHub Actions Caching-Strategie: CI/CD-Pipeline 5× beschleunigen” – dort finden Sie vertiefte Tipps.
Multi-Version-Tests sollten Sie so früh wie möglich einrichten. Warten Sie nicht, bis nach dem Go-Live etwas schiefgeht – an den weißen Bildschirm unter Node 16 denke ich heute noch.
GitHub Actions Matrix für Multi-Version-Tests konfigurieren
Multi-Version-Test-Pipeline von Grund auf: Node.js 16/18/20 auf Ubuntu und Windows
⏱️ Estimated time: 15 min
- 1
Step 1: Workflow-Datei anlegen
Erstellen Sie im Projektroot die Datei `.github/workflows/test.yml`:
• Verzeichnisstruktur: `.github/workflows/`
• Dateiname frei wählbar, empfohlen: `test.yml` oder `ci.yml` - 2
Step 2: Trigger-Bedingungen definieren
Festlegen, wann Tests laufen:
```yaml
on:
push:
branches: [main]
pull_request:
```
• Push auf main löst Tests aus
• PR-Erstellung oder -Update löst Tests aus - 3
Step 3: Matrix definieren
Versionen, Plattformen und Test-Suites konfigurieren:
```yaml
strategy:
fail-fast: false
max-parallel: 6
matrix:
node-version: [16, 18, 20]
test-suite: [unit, integration]
os: [ubuntu-latest, windows-latest]
exclude:
- node-version: 16
os: windows-latest
```
• fail-fast: false für vollständige Testergebnisse
• max-parallel: 6 begrenzt gleichzeitige Tasks
• exclude entfernt ungültige Kombinationen - 4
Step 4: Test-Schritte konfigurieren
Konkrete Testausführung definieren:
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run test:${{ matrix.test-suite }}
```
• cache: 'npm' aktiviert Dependency-Caching
• Matrix-Variablen für dynamische Versionen nutzen - 5
Step 5: Committen und verifizieren
Code pushen und Tests auslösen:
• Commit auf main oder PR erstellen
• Auf der GitHub-Actions-Seite parallele Tasks prüfen
• Testergebnisse aller Versionen kontrollieren
FAQ
Verbraucht ein Matrix-Build mehr Runner-Minuten?
Soll fail-fast true oder false sein?
• PR-Check: true empfohlen (schnelles Abbrechen, sofortiges Feedback)
• Nightly-Test: false empfohlen (vollständiger Report)
• Experimentversion: false empfohlen (kein Einfluss auf Gesamtbewertung)
Standard ist true – für die meisten PR-Szenarien ausreichend.
Was wird zuerst ausgeführt – exclude oder include?
Welcher Wert für max-parallel ist sinnvoll?
• Kleine Matrix (<10 Kombinationen): nicht setzen, Standard nutzen
• Mittlere Matrix (10–20 Kombinationen): 6–8
• Große Matrix (>20 Kombinationen): 4–6
Zu niedrig verlängert die Wartezeit, zu hoch kann Runner-Ressourcen auf einmal erschöpfen.
Wie beschleunigt man Matrix-Builds mit Caching?
Welche Variablentypen unterstützt Matrix?
• Array: `[18, 20, 22]`
• Objekt-Array: `[{name: 'a', value: 1}, {name: 'b', value: 2}]`
• String: per include hinzufügen
Arrays und Objekt-Arrays sind am lesbarsten.
7 Min. Lesezeit · Veröffentlicht am: 8. Apr. 2026 · Aktualisiert am: 9. Juli 2026
GitHub Actions Komplettleitfaden
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
GitHub Actions Cache-Strategie: CI/CD-Pipeline 5× beschleunigen
Praxisleitfaden zur GitHub Actions Cache-Strategie: vollständige Konfigurationsbeispiele von npm bis Docker, Best Practices für Cache-Keys und Performance-Vergleiche. Cache-Mechanismus beherrschen, CI/CD 5× schneller, Build-Kosten senken.
Teil 3 von 10
Nächster
GitHub Actions Matrix-Build: Parallele Tests auf mehreren Plattformen und Versionen
Praxisleitfaden zu GitHub Actions Matrix: Basis-Syntax, exclude/include, fail-fast, max-parallel und dynamische Matrix – 5 produktionsreife Workflow-Vorlagen, 60 %+ weniger Konfigurationscode.
Teil 5 von 10
Ähnliche Beiträge
GitHub Actions Einstieg: YAML-Workflow-Grundlagen und Trigger-Konfiguration

GitHub Actions Einstieg: YAML-Workflow-Grundlagen und Trigger-Konfiguration
GitHub Actions CI-Pipeline in der Praxis: Build und Test automatisieren


Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen