Monorepo CI: only build packages whose paths changed

Monorepo CI: only build packages whose paths changed

Monorepos benefit enormously from running only the affected package's pipeline rather than every package on every push. Each platform has its own way of expressing path-based filtering — and these mechanisms differ in *when* the filter is applied (at the trigger level vs. at the job level).

Conversion notes

  • GitHub: paths-filter (dorny/paths-filter) emits per-folder outputs; reuse them in jobs that should only run conditionally.
  • GitLab: `rules.changes:` is built into rules. Each job lists which paths trigger it.
  • CircleCI: requires the path-filtering orb (or dynamic config). Best handled with a setup workflow that emits a continuation config.
  • Bitbucket: `condition.changesets.includePaths:` filters per-step.

Side-by-side implementation

GitHub Actions
name: monorepo
on:
  push:
    branches: [main]
  pull_request:

jobs:
  changes:
    runs-on: ubuntu-latest
    outputs:
      web: ${{ steps.filter.outputs.web }}
      api: ${{ steps.filter.outputs.api }}
    steps:
      - uses: actions/checkout@v4
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: |
            web:
              - 'packages/web/**'
            api:
              - 'packages/api/**'

  test-web:
    needs: [changes]
    if: needs.changes.outputs.web == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd packages/web && npm ci && npm test

  test-api:
    needs: [changes]
    if: needs.changes.outputs.api == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd packages/api && npm ci && npm test
GitLab CI
stages: [test]

test:web:
  stage: test
  image: node:20
  rules:
    - changes: ['packages/web/**']
  script:
    - cd packages/web && npm ci && npm test

test:api:
  stage: test
  image: node:20
  rules:
    - changes: ['packages/api/**']
  script:
    - cd packages/api && npm ci && npm test
CircleCI
version: 2.1
setup: true

orbs:
  path-filtering: circleci/path-filtering@1.0.0

workflows:
  always-run:
    jobs:
      - path-filtering/filter:
          base-revision: main
          config-path: .circleci/continue_config.yml
          mapping: |
            packages/web/.* run-web true
            packages/api/.* run-api true
Bitbucket Pipelines
image: node:20

pipelines:
  default:
    - step:
        name: test web
        condition:
          changesets:
            includePaths: ['packages/web/**']
        script:
          - cd packages/web && npm ci && npm test
    - step:
        name: test api
        condition:
          changesets:
            includePaths: ['packages/api/**']
        script:
          - cd packages/api && npm ci && npm test

Related Tools