Jeder GitHub Actions-Workflow, den Sie je geschrieben haben, ist eine YAML-Datei. Alles davon — die Trigger, die Jobs, die Schritte, die Umgebungsvariablen, die Matrix-Strategie — wird in YAML ausgedrückt. Das bedeutet, YAML tief zu verstehen ist nicht nur akademisch: Es ist der Unterschied zwischen CI, die zuverlässig funktioniert, und CI, die mysteriöserweise um 16 Uhr an einem Freitag zusammenbricht, wenn Sie gerade ein Release ausliefern wollen.

GitHub Actions hat hervorragende Workflow-Syntax-Dokumentation, aber sie konzentriert sich auf die Actions-Features und nicht auf die darunter liegende YAML-Mechanik. Dieser Artikel behandelt beides — die Workflow-Struktur und die YAML-spezifischen Muster (und Fallstricke), die CI-Konfigurationen zum Erfolg oder Scheitern bringen.

Workflow-Struktur: Die Top-Level-Keys

Eine GitHub Actions-Workflow-Datei liegt in .github/workflows/ und hat drei erforderliche Top-Level-Keys. Die offizielle Workflow-Übersicht erklärt, wo die Datei in Ihrem Repository liegt und wie GitHub sie entdeckt:

yaml
name: CI Pipeline          # optional but shown in the Actions UI

on:                        # triggers
  push:
    branches: [main]
  pull_request:

jobs:                      # the actual work
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test
Vorsicht vor on als YAML-Boolean: In YAML 1.1 wird das bloße Wort on als Boolean true interpretiert. GitHubs Parser behandelt dies korrekt, aber wenn Sie jemals sehen, dass Ihre Workflow-Datei von einem generischen YAML-Linter markiert wird, ist das der Grund. Die sichere Form ist, es in Anführungszeichen zu setzen: "on": — obwohl GitHub Actions selbst keine Anführungszeichen verlangt.

Trigger: Der on:-Key

Der on:-Key steuert, wann Ihr Workflow läuft. Die vollständige Liste der Trigger-Ereignisse deckt alles ab, von Pull-Request-Reviews bis zu Repository-Dispatches. Hier sind die häufigsten Muster:

yaml
on:
  # Push to specific branches
  push:
    branches:
      - main
      - "release/**"       # glob pattern — quotes needed for /**
    paths-ignore:
      - "docs/**"
      - "*.md"

  # PRs targeting main
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]

  # Scheduled (cron syntax)
  schedule:
    - cron: "0 2 * * 1"   # every Monday at 2am UTC

  # Manual trigger with input
  workflow_dispatch:
    inputs:
      environment:
        description: "Target environment"
        required: true
        default: staging
        type: choice
        options: [staging, production]

Mehrzeilige run:-Befehle und YAML-Block-Skalare

Der run:-Key ist der Ort, an dem YAMLs Literal-Block-Skalar (|) seinen Wert zeigt — die yaml-multiline.info-Referenz für jede Variation von Block- und gefalteten Skalaren. Ohne ihn würden Sie Befehle mit && in einer einzigen Zeile verketten, was unleserlich ist:

yaml
steps:
  # Single line — works but hard to read
  - name: Build
    run: npm ci && npm run lint && npm run test && npm run build

  # Multi-line with literal block scalar — much better
  - name: Build
    run: |
      npm ci
      npm run lint
      npm run test -- --coverage
      npm run build

  # Folded scalar (>) joins lines with spaces — NOT what you want for shell
  # This would run as a single command with spaces where the newlines are:
  - name: Wrong for shell
    run: >
      npm ci
      npm test
Verwenden Sie für mehrzeilige Shell-Skripte immer |, niemals >. Der gefaltete Skalar faltet Zeilenumbrüche in Leerzeichen, was bedeutet, dass Ihre Shell-Befehle zu einem langen String zusammengefügt werden. Das verursacht kryptische Fehler. Der Literal-Block-Skalar | behält Zeilenumbrüche genau bei, sodass jede Zeile als separater Shell-Befehl ausgeführt wird.

Umgebungsvariablen und Secrets

Umgebungsvariablen in GitHub Actions verwenden YAML in Kombination mit der Actions-Kontext- und Ausdrucks-Syntax. So passen sie zusammen:

yaml
env:
  NODE_ENV: production         # workflow-level env var
  API_VERSION: "2.1"          # quoted to force string type

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      DEPLOY_ENV: staging      # job-level env var (overrides workflow-level)

    steps:
      - name: Deploy to staging
        env:
          API_KEY: ${{ secrets.STAGING_API_KEY }}     # step-level, from secret
          DATABASE_URL: ${{ vars.STAGING_DB_URL }}    # step-level, from variable
        run: |
          echo "Deploying to $DEPLOY_ENV"
          ./scripts/deploy.sh

Die Ausdrucks-Syntax ${{ }} ist GitHub Actions' eigene Template-Sprache, die über YAML geschichtet ist. In einigen Kontexten wird sie vor dem YAML-Parsing ausgewertet, was unerwartet mit YAMLs eigenen Anführungszeichenregeln interagieren kann. Im Zweifelsfall setzen Sie Werte, die mit ${{ beginnen, in doppelte Anführungszeichen.

Matrix-Strategie: Build über mehrere Konfigurationen

Die Matrix-Strategie ist eines der mächtigsten Features von GitHub Actions — und sie wird vollständig in YAML ausgedrückt. Sie führt Ihren Job einmal für jede Kombination von Matrix-Werten aus:

yaml
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false         # don't cancel other matrix jobs on failure
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: ["18", "20", "22"]
        exclude:
          - os: windows-latest
            node: "18"         # skip this combination

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

Diese einzelne Job-Definition erzeugt bis zu 9 parallele Läufe (3 OS × 3 Node-Versionen, minus 1 ausgeschlossene). Die YAML-Matrix-Werte sind einfache Arrays — das Einzige, worauf man achten muss, ist, dass Versionsnummern wie 18 als "18" in Anführungszeichen gesetzt werden sollten, um sie als Strings zu behalten. Ohne Anführungszeichen parst YAML sie als Integer und einige Actions könnten sich beschweren.

Bedingte Schritte mit if:

Der if:-Key ermöglicht es Ihnen, Schritte basierend auf Bedingungen zu überspringen. Er verwendet GitHubs Ausdruckssprache, keine einfachen YAML-Werte:

yaml
steps:
  - name: Run tests
    run: npm test

  - name: Upload coverage
    if: success() && github.ref == 'refs/heads/main'
    uses: codecov/codecov-action@v4

  - name: Notify on failure
    if: failure()
    uses: slackapi/slack-github-action@v1
    with:
      slack-message: "Build failed on ${{ github.ref }}"
      channel-id: "C12345ABC"
    env:
      SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

  - name: Deploy (only on tag push)
    if: startsWith(github.ref, 'refs/tags/v')
    run: ./scripts/deploy.sh production

Wiederverwendbare Workflows

Um Duplikationen repository-übergreifend zu eliminieren (nicht nur innerhalb einer Datei), unterstützt GitHub Actions wiederverwendbare Workflows. Der aufgerufene Workflow verwendet on: workflow_call: und der Aufrufer verwendet uses: auf Job-Ebene — nicht auf Schritt-Ebene:

yaml
# .github/workflows/reusable-test.yml (the reusable workflow)
on:
  workflow_call:
    inputs:
      node-version:
        required: false
        type: string
        default: "20"
    secrets:
      NPM_TOKEN:
        required: true

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci && npm test
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml
# .github/workflows/ci.yml (the caller)
on: [push, pull_request]

jobs:
  run-tests:
    uses: my-org/shared-workflows/.github/workflows/reusable-test.yml@main
    with:
      node-version: "22"
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Die häufigsten YAML-Fehler in GitHub Actions

  • Falsche Einrückung bei Schritten. Schritte müssen unter steps: mit konsistenten Leerzeichen eingerückt sein. Ein einziges zusätzliches oder fehlendes Leerzeichen verschiebt einen Schritt aus seinem Job.
  • Versionsnummern ohne Anführungszeichen. node-version: 20 übergibt einen Integer; einige Actions erwarten einen String. Verwenden Sie node-version: "20" zur Sicherheit.
  • > statt | für Shell-Skripte verwenden. Gefaltete Skalare kollabieren Zeilenumbrüche. Ihr mehrzeiliges Skript wird ein langer String und schlägt fehl.
  • Fehlende Anführungszeichen bei Glob-Mustern. Muster wie release/** enthalten *, das YAML als Alias interpretieren kann. Setzen Sie Glob-Muster immer in Anführungszeichen.
  • Secrets in if:-Bedingungen verwenden. GitHub maskiert Secrets in Logs, erlaubt sie aber nicht in if:-Ausdrücken. Verwenden Sie stattdessen eine Umgebungsvariable.
  • fail-fast: false in Matrix-Jobs vergessen. Standardmäßig werden alle anderen Matrix-Jobs abgebrochen, wenn ein Matrix-Job fehlschlägt. Beim Debugging ist das normalerweise nicht das, was man will.

Fazit

GitHub Actions-Workflows sind grundlegend YAML-Dateien — das Verständnis von YAMLs Literal-Block-Skalaren, Anführungszeichenregeln und Typumwandlung übersetzt sich direkt in das Schreiben zuverlässigerer CI. Die häufigsten Fehler entstehen durch Einrückungsfehler, nicht angeführte Werte, die in den falschen Typ umgewandelt werden, und das Verwenden des falschen mehrzeiligen String-Operators für Shell-Skripte. Holen Sie sich diese drei Dinge richtig und die meisten Workflow-Debugging-Sitzungen werden unkompliziert. Verwenden Sie den YAML-Validator, um Syntaxfehler vor dem Push abzufangen, und den YAML-Formatierer, um konsistente Einrückung in Ihren Workflow-Dateien durchzusetzen.