Open chat

← All posts

CI/CDGitHub Actions

GitHub Actions: matrices and required checks without YAML sprawl

Centralizing lint, typecheck, and tests in one workflow—matrixed where it matters, protected by branch rules.

CI exists to give every contributor the same quality bar before merge. I avoid copy-pasting workflows across repositories; instead I lean on matrices for Node versions or package managers, service containers for integration tests, and required status checks that match the jobs GitHub actually emits.

Matrix for runtime coverage

name: ci
on:
  pull_request:
    branches: [main]

jobs:
  verify:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        node: [18.x, 20.x]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck
      - run: npm test -- --ci --coverage --maxWorkers=2

fail-fast: false surfaces all matrix legs on a bad change instead of hiding failures behind the first red cell.

Integration tests with Postgres

Declare services at the job level; inject connection strings via environment variables so tests never assume hard-coded localhost quirks that only appear in CI.

Governance

Protect main with required checks whose names match the jobs above. Optional checks and noisy notifications train teams to ignore red builds—required checks should be few and meaningful.

Takeaway: CI is a product: clarity, caching, and branch protection matter as much as the scripts themselves.

← Back to portfolio