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: 0so the diff base is available. - Derive the changed package list and write it to
$GITHUB_OUTPUTas 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
How to Build a Dynamic Matrix From JSON in GitHub ActionsGenerate a GitHub Actions matrix at runtime by having a setup job emit JSON and a downstream job read it with…
How to Run a Matrix Only on Certain Events in GitHub ActionsVary a GitHub Actions matrix by event, running a small matrix on pull requests and the full one on push to ma…