Automated reviews instead of manually hunting for reviewers
The CODEOWNERS file automatically assigns pull and merge requests to the right reviewers, based on which file paths changed. This article explains the syntax and path matching rules, shows how to combine CODEOWNERS with branch protection on GitHub and GitLab, provides practical examples for Magento 2 and Hyva projects, and describes how a team keeps the file current over time.
Table of Contents
- 1. What the CODEOWNERS file does and why it automates reviews
- 2. File location and format: GitHub, GitLab, and Bitbucket compared
- 3. Syntax and path matching: glob patterns and the precedence rule
- 4. Negation, wildcards, and the limits of pattern matching
- 5. Combining CODEOWNERS with branch protection so it actually applies
- 6. Teams versus individuals as code owners
- 7. Practical example: CODEOWNERS for a Magento 2 / Hyva project
- 8. Common pitfalls when using CODEOWNERS
- 9. Maintaining CODEOWNERS as team structure and ownership shift
- 10. Summary
- 11. FAQ
1. What the CODEOWNERS file does and why it automates reviews
The CODEOWNERS file is a simple text file that GitHub, GitLab, and Bitbucket parse natively to automatically suggest the right reviewers on every pull or merge request. Instead of someone manually figuring out who is responsible for a changed folder, the platform matches the changed file paths against the rules in the file and automatically adds the listed people or teams as reviewers. No extra tool and no bot is required, the feature is built directly into the platform.
The real value shows up in day to day team work: knowledge about a specific area, say the checkout module or the CI pipeline, stays attached to the code instead of living only in one person's head. New team members immediately see who the right contact is for questions about a module, and reviews reliably land with someone who has actual context instead of whoever happens to be free next. Especially in growing repositories with multiple teams, this prevents a lot of shallow reviews that add little substance.
2. File location and format: GitHub, GitLab, and Bitbucket compared
GitHub looks for the file in exactly three possible locations: the root directory as CODEOWNERS, under docs/CODEOWNERS, or under .github/CODEOWNERS. If several of these files exist at once, GitHub uses only the first one found in that order, the others are ignored entirely. In practice, .github/CODEOWNERS has become the convention, since it sits alongside workflows and issue templates in the same hidden folder and is easier to find as a result.
GitLab allows the same three paths and additionally supports .gitlab/CODEOWNERS, but also supports named sections in square brackets, which let you define different approval groups with their own minimum number of reviewers. Bitbucket Cloud requires the file exclusively in the root directory under the name CODEOWNERS. Anyone running multiple platforms in parallel, say GitHub for open source mirrors and GitLab internally, should settle on a single location and document it, so no one accidentally maintains a second, ineffective copy.
3. Syntax and path matching: glob patterns and the precedence rule
Each line in the CODEOWNERS file consists of a path pattern followed by one or more owner entries, separated by whitespace. The path patterns follow the same glob syntax as .gitignore: a single asterisk stands for any characters within one path segment, a double asterisk for any nesting depth, and a trailing slash marks a directory along with all of its contents. Comments start with a hash sign, blank lines are ignored.
The most important, and also the most commonly misunderstood, mechanism is the precedence rule: it's not the most specific pattern that wins, but simply the last pattern in the file that matches a given path. If you define a broad rule for app/code/** near the top and a more specific one for a single module below it, the more specific rule must be placed further down, otherwise it gets silently overridden by the broader rule above, even though it looks more precise in a diff. This ordering logic sets CODEOWNERS apart from most other configuration formats that use glob patterns.
# CODEOWNERS: rules are evaluated top to bottom,
# but the LAST matching pattern wins, not the most specific one
# Default fallback owner for everything not matched below
* @mironsoft/backend-team
# Frontend team owns all Hyva theme templates and styles
/app/design/frontend/** @mironsoft/frontend-team
# A more specific override MUST come after the broader rule above,
# otherwise the broader rule silently wins for this path
/app/design/frontend/Mironsoft/default/web/tailwind/** @mironsoft/frontend-lead
4. Negation, wildcards, and the limits of pattern matching
Unlike .gitignore, the CODEOWNERS syntax has no exclamation mark for negation. There is no way to explicitly exempt a file from an owner assignment defined earlier. The only way to exclude a subpath from a broader rule is to place a more specific rule further down in the file that matches that path, if necessary even with an empty owner field, which simply removes any automatic assignment for that area.
Precision matters with wildcards: a single asterisk does not match across directory boundaries, recursive matching across an arbitrary number of levels always requires the double asterisk. A leading slash anchors the pattern to the repository root, without one the pattern matches the given name anywhere in the tree, which can produce surprisingly many hits for generic names like config or tests. A quick check in the GitHub web UI under settings reliably shows, before you commit, which paths a rule actually covers.
5. Combining CODEOWNERS with branch protection so it actually applies
Without additional configuration, the CODEOWNERS file is purely informational: the suggested reviewers get added automatically, but nothing stops a merge from going through without their approval. Under time pressure, a suggested reviewer is often quickly removed or simply ignored, and the file effectively loses all its power. Only combining it with a binding rule turns the suggestion into an actual requirement for merging.
On GitHub, this means enabling Require review from Code Owners in the branch protection rules for the target branch, in addition to the general minimum number of approvals. On GitLab, the equivalent setting lives under the Merge Request Approval Settings as Require approval from code owners, and can be combined with a project wide or group wide rule. In both cases, a merge can only complete once at least one person from every affected CODEOWNERS line has actually approved, regardless of how many other colleagues already gave a general approval.
{
"required_status_checks": null,
"enforce_admins": true,
"required_pull_request_reviews": {
"required_approving_review_count": 1,
"require_code_owner_reviews": true,
"dismiss_stale_reviews": true
},
"restrictions": null
}
6. Teams versus individuals as code owners
CODEOWNERS entries can reference either individual usernames prefixed with an at sign, or entire teams in the format @organization/team-name. Teams have a decisive advantage: if one person is out due to vacation or illness, another team member automatically steps in without anyone needing to edit the file. Individuals listed as the sole owner, on the other hand, quickly become a bottleneck, especially for modules with a high rate of change, because every merge then waits on that one person's availability.
A prerequisite for teams as owners is that they actually have write access to the repository, otherwise they show up in the owner assignment but technically cannot be added as reviewers and the rule falls flat. For highly critical, rarely changed paths like payment processing or security configuration, a named individual or a very small team is often still the better choice, precisely because not every team member should automatically have approval authority there.
7. Practical example: CODEOWNERS for a Magento 2 / Hyva project
In a Magento 2 project with Hyva Theme, owners can be split sensibly along functional responsibility: the frontend team owns app/design/frontend/**, while the backend team is responsible for app/code/Vendor/**/**. Particularly sensitive paths such as db_schema.xml files, which declaratively describe database changes, should also be covered by the lead developer, since a broken schema change can, in the worst case, cause data loss. CI/CD configuration files deserve their own, narrower owner assignment as well.
The reason for the separate rule on .github/workflows/** or .gitlab-ci.yml is simple: changes to the pipeline potentially affect every deploy and every other team member, which is why the person responsible for infrastructure should typically own that path, regardless of who changes the business logic around it. This granular split ensures that a plain frontend commit in the template folder doesn't needlessly wait on a review from the backend lead, while a schema update reliably reaches the right person.
# .github/CODEOWNERS for a Magento 2 / Hyva project
# Fallback: platform/backend team reviews everything by default
* @mironsoft/backend-team
# Hyva theme: templates, layout XML and Tailwind config
/app/design/frontend/Mironsoft/default/** @mironsoft/frontend-team
# Custom modules: module owner reviews module-specific logic
/app/code/Mironsoft/SeoSuite/** @mironsoft/seo-module-owner
/app/code/Mironsoft/Core/** @mironsoft/backend-lead
# Declarative schema changes always need the lead developer,
# a broken db_schema.xml can cause data loss on deploy
**/db_schema.xml @mironsoft/lead-dev
# Pipeline and deployment config: infrastructure owner only
/.github/workflows/** @mironsoft/devops-lead
/.gitlab-ci.yml @mironsoft/devops-lead
8. Common pitfalls when using CODEOWNERS
The most common pitfall is staleness: when someone leaves the team or changes roles, their username stays in the file until someone actively cleans it up. GitHub and GitLab provide no automatic warning for this, the rule simply remains in place and fails on every matching pull request, because a former member without access cannot be added as a reviewer. An overly broad pattern, such as a single asterisk covering the entire repository, also creates a bottleneck once every merge suddenly waits on the same small group.
The second major pitfall is silent syntax errors: a typo in a username, a missing at sign, or a misspelled path does not produce an error message, the line simply matches nothing and the assignment silently doesn't happen, without anyone noticing. Case sensitivity matters too: path patterns are case sensitive, while usernames may or may not be depending on the platform, which regularly leads to unnoticed inconsistencies during manual maintenance. Regular test runs through the GitHub code owners preview reduce this risk noticeably.
# Quick manual check: does every referenced user still have repo access?
$ grep -oE '@[a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)?' CODEOWNERS | sort -u
@mironsoft/backend-team
@mironsoft/frontend-team
@mironsoft/lead-dev
@ex-employee
# Cross-check against current collaborators via GitHub CLI
$ gh api repos/mironsoft/shop/collaborators --jq '.[].login'
mironsoft-lead
frontend-dev-1
backend-dev-2
# @ex-employee is missing here: stale entry, rule silently fails to assign
# GitHub renders a live preview of unmatched or invalid lines
# under Settings > Code owners, always check it before merging changes
9. Maintaining CODEOWNERS as team structure and ownership shift
The CODEOWNERS file itself should appear in the file as a protected path, so that changes to it must always be approved by the tech leads or team leadership, instead of any developer being free to add themselves as an owner. A fixed cadence, say a short check every quarter as part of a team retro, reliably surfaces stale entries before they silently block reviews for months.
For larger organizations, automated linting in the CI pipeline is worth the investment too, for example with the open source tool codeowners-validator, which checks whether every referenced user and team still exists, actually has write access, and whether every rule matches at least one file in the repository. That way stale or ineffective lines become visible right in the pull request, instead of only surfacing months later after a failed review attempt.
# .github/workflows/codeowners-lint.yml
name: Lint CODEOWNERS
on:
pull_request:
paths:
- '.github/CODEOWNERS'
- 'CODEOWNERS'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Fails the build if a referenced user/team no longer exists
# or has no write access, or a pattern matches zero files
- name: Validate CODEOWNERS
uses: mszostok/codeowners-validator@v0.7.4
with:
checks: "files,duppatterns,syntax,owners"
github_access_token: ${{ secrets.GITHUB_TOKEN }}
The following overview shows the practical difference between a purely informational CODEOWNERS file and a file that is additionally enforced through branch protection.
| Scenario | Without branch protection enforcement | With CODEOWNERS + branch protection | Impact |
|---|---|---|---|
| Ignoring a suggested reviewer | Merge still possible | Merge blocked until approved | Enforcement instead of a suggestion |
| Team member leaving | File goes stale unnoticed | CI linting flags the invalid entry | Stale rules surface immediately |
| Critical path like db_schema.xml | Any reviewer is sufficient | Only the defined owner can approve | Protection against risky schema changes |
| New team member | Has to manually ask who owns what | Automatic assignment by path | Faster onboarding |
| Changing CODEOWNERS itself | Anyone can add themselves | Only the tech lead can change the file | Controlled ownership assignment |
Mironsoft
Git workflows, code reviews, and CI/CD pipelines for PHP and Magento teams
Ready to make code ownership binding for your team?
We help development teams set up CODEOWNERS files, branch protection rules, and review processes that clearly assign responsibility and reliably route reviews to the right people.
CODEOWNERS setup
Path based owner assignment for frontend, backend, and schema changes
Branch protection audit
Review existing rules and switch to enforced code owner approvals
CI/CD linting
Automated checks of the CODEOWNERS file for stale entries
10. Summary
The CODEOWNERS file solves a simple but important problem: it ties knowledge about responsibility directly to file paths, instead of leaving it implicitly in one person's head. GitHub, GitLab, and Bitbucket parse the file natively and automatically suggest the right reviewers on every pull or merge request, based on a glob syntax where the last matching pattern always wins, not the most specific one. Without additional configuration, though, the file stays purely informational and can be ignored at any time.
Only combining it with Require review from Code Owners on GitHub, or Require approval from code owners on GitLab, turns the suggestion into an actual requirement for merging. For Magento 2 and Hyva projects, a granular split across frontend, backend, database schema, and CI/CD configuration pays off, maintained through a fixed review cadence and automated linting in the pipeline, so stale entries and silent syntax errors surface early instead of quietly blocking reviews for months.
CODEOWNERS at a Glance
What CODEOWNERS does
Automatically assigns matching reviewers to pull and merge requests, based on the changed file paths.
Precedence rule
The last matching pattern in the file wins, not the most specific one.
Only binding with branch protection
Enable Require review from Code Owners (GitHub) or Require approval from code owners (GitLab).
Maintenance over time
Require review for CODEOWNERS changes themselves and use CI linting to catch stale entries.