Skip to content
Latchkey

How to Build a Matrix From Changed Files in GitHub Actions

Detect which directories changed, emit them as JSON, and the matrix runs only over the affected packages.

A setup job diffs the push, maps changed files to package names, prints a JSON array, and a downstream matrix consumes it with fromJSON.

Steps

  • Check out with fetch-depth: 0 so the diff base is available.
  • Derive the changed package list and write it to $GITHUB_OUTPUT as JSON.
  • Fan the matrix out over fromJSON(needs.detect.outputs.pkgs).

Workflow

.github/workflows/ci.yml
jobs:
  detect:
    runs-on: ubuntu-latest
    outputs:
      pkgs: ${{ steps.diff.outputs.pkgs }}
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - id: diff
        run: |
          CHANGED=$(git diff --name-only origin/main... | cut -d/ -f2 | sort -u \
            | jq -R . | jq -sc .)
          echo "pkgs=$CHANGED" >> "$GITHUB_OUTPUT"
  build:
    needs: detect
    if: needs.detect.outputs.pkgs != '[]'
    runs-on: ubuntu-latest
    strategy:
      matrix:
        pkg: ${{ fromJSON(needs.detect.outputs.pkgs) }}
    steps:
      - run: echo "Building ${{ matrix.pkg }}"

Gotchas

  • Guard the build job with if: ... != '[]' so an empty list does not error.
  • The diff base differs on pull_request; use the merge base rather than a fixed branch.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →