@@ · process @@

CODEOWNERS best practices that keep reviews honest

Othman Shareef · August 31, 2026 · 6 min read

CODEOWNERS is one of those GitHub features that teams set up once, half correctly, and never look at again until a release is blocked by a review request to someone who left the company in March. Most CODEOWNERS best practices are not clever tricks; they are consequences of how the file actually behaves, which is documented in GitHub’s code owners docs and routinely misremembered. Worth getting the mechanics right first, then the judgment calls.

CODEOWNERS best practices start with the mechanics

The behaviors that matter, straight from the docs. GitHub searches for the file in .github/, the repository root, then docs/, and uses the first one it finds. Owners are automatically requested for review when a PR modifies code they own, though draft PRs wait until they are marked ready. Teams can be owners via @org/team-name, but the team must be visible and hold write permission on the repo, even if all its members already have write access directly.

Two sharp edges deserve special respect. First, the syntax looks like gitignore but is not: negation with ! and character ranges with [ ] do not work. Second, invalid lines are silently skipped, so a typo does not fail loudly; it just quietly stops routing reviews. If your CODEOWNERS file has drifted, nothing tells you.

Last match wins, so order your file like it matters

The docs say it plainly: order is important, and the last matching pattern takes precedence. That is the opposite of the first-match instinct people carry over from firewall rules and route tables, and it is the single most common CODEOWNERS bug. The working structure is broad-to-specific:

  • A default owner at the very top (* @org/eng), if you want one at all.
  • Directory-level ownership in the middle.
  • High-risk overrides at the bottom (/payments/ @org/payments), where nothing can shadow them.

Write it in the other order and your carefully chosen payments owners are silently overridden by the catch-all. Because lines fail silently, the only way you find out is by noticing the wrong people getting review requests.

Own directories, not files

File-level ownership rots at the speed of refactoring: files get renamed, split, and moved, and each move silently orphans a rule. Directory-level ownership tracks the actual shape of responsibility (a service, a package, a surface) and survives file churn within it. If you find yourself needing file-level rules, that is usually a signal the directory mixes concerns that want to be separated anyway. The same logic that makes directories the right unit for config and infra review makes them the right unit for ownership: the boundary is architectural, not alphabetical.

Avoid the everything-owner

The most tempting line in any CODEOWNERS file is * @that-one-senior-dev. It feels safe: every change gets an experienced pair of eyes. What it actually creates is a single human queue in front of every merge. That person’s vacation becomes a release freeze, their busy week becomes everyone’s slow week, and the volume guarantees the reviews become skims. When required review from code owners is enabled, an approval from any listed owner satisfies the requirement, so the honest fix is listing a team: the requirement stays strong while the load spreads. An everything-owner is a bus factor of one, enforced by branch protection.

CODEOWNERS as tier encoding

The most useful mental model: CODEOWNERS is where you encode review tiers by blast radius so the platform enforces them. Auth, payments, migrations, and public API directories get named owning teams plus required code-owner review in branch protection. Ordinary application code gets team-level ownership with no required gate. Docs and internal tooling may get no entry at all. The file becomes a readable statement of what the team considers dangerous, and the expensive reviewers are automatically routed to exactly the changes that warrant them, with no lost review requests along the way.

Keep it honest: audit for stale owners

A CODEOWNERS file is a claim that certain people will review certain changes. Claims go stale. The owner who changed teams, the person who left, the team that was reorganized away: each becomes either a review request into the void or, worse, a required approval nobody can give. A quarterly audit is cheap and mostly mechanical: list every owner, check they still exist and still have write access, then check the last few PRs in their area and confirm they actually reviewed. An owner who has not reviewed anything in their directory for two quarters is not an owner; they are a label. Either they recommit, or the line changes to the team that has actually been doing the reviewing. The file should describe reality, because branch protection will enforce whatever it says, real or not.

One last habit that keeps all of this working: treat changes to CODEOWNERS itself as reviewable code, not admin housekeeping. A one-line edit can silently reroute every review in a subsystem or shadow a high-risk override, and because invalid lines are skipped rather than rejected, a typo ships as easily as a decision. Give the file its own ownership entry so edits to it always get a deliberate second pair of eyes.

Frequently asked questions

Where does the CODEOWNERS file go?

GitHub looks for CODEOWNERS in the .github/ directory, the repository root, or docs/, in that order, and uses the first file it finds. The file is read per branch, so different branches can define different owners. Most teams use .github/CODEOWNERS to keep the repo root uncluttered and the file next to other GitHub configuration.

How does CODEOWNERS decide which owner applies when patterns overlap?

Last match wins. GitHub evaluates the file top to bottom and the last pattern that matches a changed file takes precedence, the opposite instinct of firewall-style first-match rules. Put broad patterns like a default owner at the top and specific overrides like /billing/ below them, or the specific rules will never fire.

Can a GitHub team be a code owner?

Yes, using the @org/team-name form, and it is usually the right choice: individuals go on vacation and leave companies. The team must be visible and must have explicit write permission on the repository, even when every member already has write access individually. When review from code owners is required, one approval from any listed owner satisfies it.

← All posts