A practical pattern for monorepo CI with path filters, matrix builds, caching, and deployment guards that keep feedback fast as teams scale.
Monorepos improve shared ownership and cross-service refactoring, but CI pipelines can become slow and expensive when every pull request runs every job. The fix is not one giant workflow file. The fix is a clear build contract with targeted execution, predictable caching, and strict release gates.
Use three layers:
name: ci
on:
pull_request:
push:
branches: [main]
jobs:
detect:
runs-on: ubuntu-latest
outputs:
services: ${{ steps.set.outputs.services }}
steps:
- uses: actions/checkout@v4
- id: set
run: |
CHANGED=$(git diff --name-only origin/main...HEAD | cut -d/ -f1,2 | sort -u)
SERVICES=$(echo "$CHANGED" | grep '^services/' | cut -d/ -f2 | jq -R -s -c 'split("\n")[:-1]')
echo "services=$SERVICES" >> $GITHUB_OUTPUT
This keeps you from building unrelated applications when docs or other folders change.
test:
needs: detect
if: ${{ needs.detect.outputs.services != '[]' }}
strategy:
matrix:
service: ${{ fromJson(needs.detect.outputs.services) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint --workspace=services/${{ matrix.service }}
- run: npm run test --workspace=services/${{ matrix.service }}
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
Pair this with protected environments and manual approvals for production.
With this model, monorepo CI stays fast as service count grows.
Get the latest tutorials, guides, and insights on AI, DevOps, Cloud, and Infrastructure delivered directly to your inbox.
A production-focused guide to Azure DevOps: standardized YAML templates, secure service connections, rollout safety, and measurable delivery reliability.
How to implement Backstage with real templates, scorecards, and golden paths so internal platform work reduces delivery friction.
Explore more articles in this category
Every CI/CD platform claims to be fast and easy. The real differences are in pricing, self-hosting, and where each one falls apart at scale. This is the map.
Woodpecker forked Drone when the license changed. Here's how the two compare for small teams and homelabs that just want simple container-native CI.
Buildkite runs the control plane and lets you own the compute; Actions keeps everything close to your repo. Here's how they actually differ once you scale.
Evergreen posts worth revisiting.