Advanced GitHub Actions Patterns
Advanced GitHub Actions Patterns
GitHub Actions can do far more than basic CI. Matrix builds, reusable workflows, composite actions, and smart caching can dramatically speed up your pipelines and reduce duplication.
Matrix Builds
Test across multiple versions, operating systems, or configurations in parallel:
jobs:
test:
strategy:
matrix:
node: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
exclude:
- node: 18
os: macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
Dynamic Matrix
Generate the matrix from a previous step:
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.find.outputs.packages }}
steps:
- uses: actions/checkout@v4
- id: find
run: |
packages=$(ls packages/*/package.json | jq -R -s -c 'split("\n") | map(select(. != "")) | map(split("/")[1])')
echo "packages=$packages" >> "$GITHUB_OUTPUT"
test:
needs: prepare
strategy:
matrix:
package: ${{ fromJson(needs.prepare.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cd packages/${{ matrix.package }} && npm test
Reusable Workflows
Define a workflow once and call it from multiple repositories:
.github/workflows/ci-template.yml (in shared repo)
on:
workflow_call:
inputs:
node-version:
type: string
default: "20"
secrets:
NPM_TOKEN:
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: npm run build
- run: npm test
Call it from another repo:
jobs:
ci:
uses: my-org/shared-workflows/.github/workflows/ci-template.yml@main
with:
node-version: "20"
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Composite Actions
Bundle multiple steps into a single reusable action:
.github/actions/setup-project/action.yml
name: Setup Project
description: Install deps and build
inputs:
node-version:
default: "20"
runs:
using: composite
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: npm
- run: npm ci
shell: bash
- run: npm run build
shell: bash
Smart Caching
Cache dependencies and build outputs to speed up runs:
- uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
.next/cache
key: ${{ runner.os }}-next-${{ hashFiles('/package-lock.json') }}-${{ hashFiles('/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-next-${{ hashFiles('**/package-lock.json') }}-
${{ runner.os }}-next-
Secrets Management
Use environment-level secrets for deployment credentials:
jobs:
deploy:
environment: production
runs-on: ubuntu-latest
steps:
- run: deploy --token ${{ secrets.DEPLOY_TOKEN }}
Concurrency Control
Prevent duplicate runs and cancel outdated deployments:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
Conclusion
Use matrix builds for cross-platform testing, reusable workflows to share CI logic across repos, composite actions to bundle common steps, and aggressive caching to cut build times. These patterns transform GitHub Actions from basic CI into a powerful automation platform.