Back to Blog

5 Advanced CODEOWNERS Patterns to Kill Review Fatigue

5 Advanced CODEOWNERS Patterns to Kill Review Fatigue

There’s a specific kind of exhaustion that comes from being tagged in every single pull request just because you happened to be the one who initialized the repository three years ago. You’re not the expert on the billing logic anymore, but because the CODEOWNERS file says * @original-dev, your notifications are a graveyard of irrelevant pings.

Most teams treat CODEOWNERS as a "set it and forget it" chore. They throw a single wildcard in there and wonder why their lead devs are burnt out and their PRs take three days to merge. If you want to actually ship code without the friction, you need to move past global ownership and start using these more surgical patterns.

1. The "Infrastructure as Code" Gatekeeper

If you’re using GitHub Actions, Terraform, or even just complex package.json scripts, you don't want every frontend dev accidentally tweaking the CI/CD pipeline or upgrading a critical dependency without a second pair of eyes from the Ops or Platform team.

Instead of a broad catch-all, isolate the files that can actually break the house.

# Protect the CI pipelines
/.github/workflows/ @platform-engineering

# Protect infrastructure definitions
*.tf @devops-team
/scripts/deploy.sh @devops-team

# Keep an eye on dependency changes
/package-lock.json @tech-leads
/yarn.lock @tech-leads

Why this works: It stops "drive-by" changes to critical infra. A dev fixing a CSS bug shouldn't have to wait for an Ops review, but if they touch the deploy.sh script, the right people are notified instantly.

2. Using "Negative Space" with Path Precedence

GitHub processes CODEOWNERS from top to bottom. The last matching pattern wins. You can use this to create a "Global but Specific" hierarchy. This is great for large monorepos where you want a general team to see everything *except* the specialized modules.

# Default fallback for the whole repo
* @general-eng-team

# Overrides: The most specific rules go at the bottom
/src/services/billing/ @billing-squad
/src/services/auth/ @security-team

In this setup, if a PR touches src/services/billing/invoice.ts, only @billing-squad is requested. If it touches README.md, it goes to @general-eng-team. It prevents the "double ping" where everyone gets notified and everyone assumes someone else is handling it.

3. The Cross-Cutting Glob (The "Test" Specialist)

Sometimes ownership isn't about a directory; it's about a *type* of work. If you have an SDET (Software Development Engineer in Test) team or a group of QA-focused devs, you can route all testing changes to them regardless of where they live in the file tree.

# Any file ending in .test.js or .spec.ts
**/*.test.js @qa-automation
**/*.spec.ts @qa-automation

# Route end-to-end tests specifically
/tests/e2e/ @qa-automation @product-leads

The double asterisk (**) is your best friend here. It looks deep into every subdirectory. This ensures that even if a developer adds a new feature folder, the tests they write inside it are automatically routed to the people who care about test coverage and quality.

4. Documentation and Schema Guardians

Documentation and API schemas are often the first things to drift. You can kill this drift by assigning "Librarians"—people who ensure the public-facing docs or GraphQL schemas stay consistent with the code.

# Keep the docs team in the loop
/**/*.md @docs-team
/docs/ @docs-team

# API Schema ownership
**/*.graphql @api-guild
/openapi.yaml @api-guild

The Gotcha: Be careful with .md files. If you have a README.md in every subfolder, your @docs-team might get overwhelmed. If that's the case, stick to the root /docs/ folder or specific high-level files.

5. Leverage Teams, Not Individuals

This is less of a pattern and more of a survival rule: Never put an individual's username in CODEOWNERS.

People go on vacation. People leave companies. People move to different squads. If you use @jdoe, and J. Doe is in Hawaii, your PR is stuck in limbo.

# Bad
/src/legacy/ @senior-dev-who-might-quit

# Good
/src/legacy/ @core-maintainers-team

By using GitHub Teams, you get a few massive benefits:
1. Load Balancing: GitHub can be configured to "Round Robin" or "Load Balance" reviews among team members.
2. On-Call Friendly: You can rotate people in and out of the team without touching the code.
3. Visibility: It’s clear which *group* is responsible for the logic, making it easier for new hires to know who to ping on Slack.

One final thing: The "Empty" Owner

If you have a file that needs to be updated frequently (like a version log or a changelog) and you *don't* want it to trigger a required review from the global owners, you can technically leave it blank or assign it to a "bot" user that auto-approves. However, usually, if you want to explicitly say "nobody owns this/this doesn't need special routing," you simply let it fall through to the most general rule.

The goal isn't to have a 500-line CODEOWNERS file. The goal is to make sure that when a notification hits an engineer's inbox, they know it's actually their job to look at it. Everything else is just noise.