Chapter 28Lesson 03~195 minutes

Monorepos, Path Filters, Changed-File Detection, and Selective Pipelines: Configuration, Design Patterns, and Trade-Offs

Choose native filters, custom diffs, dependency-aware selectors, no-op aggregation, scheduled full suites and matrix strategies without making correctness depend on skipping.

Design choicesNative filtersAggregationFull suiteTrade-offs

Learning objectives

  • Choose between native path filters and an in-workflow custom diff based on required-check and dependency needs.
  • Compare component-local selection with dependency-aware closure.
  • Design a stable no-op/aggregate required check and an independent full-suite lane.
  • Choose static versus generated matrices using evidence and maintenance cost.
  • Evaluate latency, auditability, portability and failure isolation trade-offs.

1. Design question: where should selection live?

Selective CI has several legitimate implementation points. GitHub can filter an entire workflow before run creation. A selector job can compute changes after a run exists. A static matrix can evaluate per-cell conditions. A generated matrix can create only the required cells. These choices affect branch protection, observability and failure modes differently; there is no universal “best monorepo YAML.”

2. Native path filter versus custom diff

Choice Strength Risk Best fit
Native paths No runner cost when unmatched; simple glob rules Required workflow may disappear/Pending; no dependency closure by itself; platform diff limits Optional workflows with simple direct ownership.
Custom selector job Full evidence; dependency graph; fallback logic; stable aggregate check Consumes a small runner job; must maintain Git-history logic Required CI and dependency-aware monorepos.
Hybrid Native filter for clearly optional lanes + in-workflow selector for required lane Two rule sets can drift Large repo with multiple service levels.

Do not duplicate the same critical ownership logic in many workflow paths blocks. If component dependencies are nontrivial, centralize the graph and test it.

3. Component-local versus dependency-aware selection

Component-local selection asks “did files under this component change?” Dependency-aware selection asks “could this component’s behavior change because any dependency changed?” The second question is what correctness requires.

Change Local selector Dependency-aware selector
apps/api/** api api
apps/web/** web web
libs/shared/** shared only / maybe none api + web
root lockfile/build config often none full fallback or all consumers
selector graph itself maybe none full suite + selector contract tests

4. Skip workflow versus no-op required check

A required workflow skipped before run creation can leave a Pending check. A job skipped by a condition behaves differently and can report success. The safer required-check pattern is one stable aggregate job inside an always-created PR workflow; that job validates the selector and selected job conclusions.

If zero components are selected, the aggregate records why and succeeds. If selection errors, dependency-contract checks fail, or any selected job fails, it fails.

5. PR incremental suite versus scheduled/manual full suite

PR selection optimizes feedback. A broad full suite verifies the selector’s blind spots and integration assumptions independently. The full lane must not reuse the same buggy selector to decide what “all” means; it should enumerate the authoritative component inventory directly.

A scheduled run is not a substitute for PR protection because it happens later. It is a detection backstop. Preserve the failing selector version and change set when it exposes under-selection.

6. Static matrix versus generated matrix

Pattern Pros Cons Use when
Static matrix + cell if Inventory visible in YAML Verbose skip logic Small stable component count.
Generated matrix Creates only selected jobs; scalable JSON/output contract becomes critical Medium/large repo with central selector.
Reusable per-component workflow Strong interface and ownership Cross-workflow aggregation/versioning complexity Platformized delivery, Chapter 29.

7. Renames and deletions require conservative semantics

A rename can cross ownership boundaries, and deletion of a shared file can break dependents. The lab avoids ambiguity with --no-renames, causing old and new paths to appear as deletion/addition. A more advanced selector may parse --name-status -z and explicitly evaluate both paths.

Do not infer “deleted means no test needed.” Deletion is still a change to the component graph.

8. Required check naming is an API contract

Branch protection and rulesets identify required checks by their reported names/source. Renaming a workflow or job can therefore affect merge governance. Keep the aggregate job name stable and document it as part of the monorepo CI interface.

9. Security, runner and cost trade-offs

Dimension Selective design implication
Security Untrusted PR paths are data; selector and tests use minimal permissions on hosted runners.
Latency Selector should be much cheaper than the work it saves.
Cost Native optional filters save all runner minutes; in-workflow selector spends one small job to preserve governance.
Auditability Retain revision pair, changed paths, mapping reasons and matrix decisions.
Portability Keep component graph in repository source rather than relying only on hosted-service UI.
Failure isolation Matrix separates component failures; fail-fast: false preserves broader evidence.

10. Worked selection scenarios

Repository Choice Prerequisites Observable proof
2 apps, no shared code Static matrix or simple path rules Stable direct ownership per-component checks + stable aggregate.
20 services + shared libraries Custom dependency-aware generated matrix Versioned graph, adequate Git history selection.json + matrix cells + full-suite contract test.
Docs preview only Native paths Not sole required gate absence of optional workflow is acceptable.
High-risk release branch PR selective + pre-release full suite Authoritative component inventory full-run evidence before promotion.
Unknown build-system file changed Full fallback Conservative policy selector records fallback reason and selects all.

11. Version-sensitive assumptions — September 10, 2026

Current GitHub.com documentation states that pull-request path filtering uses three-dot diffs, push filtering uses two-dot diffs, a push with more than 1,000 commits or a diff timeout runs rather than filters, and path evaluation examines up to the first 3,000 changed files. A workflow skipped by path/branch filtering or skip annotation can leave a required check Pending. Verify these service values again during maintenance.

12. Design summary

Use the simplest selector that can prove correctness. Native filters are excellent when a workflow is optional and ownership is direct; dependency-aware in-workflow selection is better for required monorepo CI. Keep one stable governance-facing check and an independent full-run policy.

Next lesson

Monorepos, Path Filters, Changed-File Detection, and Selective Pipelines: Diagnostics, Failure Modes, and Production Practices

Continue with the next lesson to build on the current concepts, evidence, security boundaries, and operational practices.

Knowledge check

When is native paths especially appropriate?

Why should a scheduled full suite enumerate components independently?

What should happen when a root build configuration file changes?

Why treat the aggregate job name as a contract?

What is the safer rename default?

Official references and version notes

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.