GitHub Actions Tutorial — Matrix Patterns

2 minute read

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 →

Updated: