
When you are managing a repository with multiple contributors, two things break down fast — the wrong person reviews critical code, and no one is accountable when something goes wrong.
GitHub’s CODEOWNERS file solves both problems. It automatically assigns the right reviewers when specific files or directories are changed, and when combined with branch protection rules, it enforces those reviews before any merge can happen.
This guide covers everything — syntax, permissions, team setup, branch protection, real-world patterns, common mistakes, and best practices for 2026.
What Is a GitHub CODEOWNERS File?
A CODEOWNERS file is a plain text file that defines who owns specific parts of a codebase. When someone opens a pull request that touches files matching a pattern in CODEOWNERS, GitHub automatically requests a review from the assigned owners.
Why it matters:
- Ensures subject-matter experts review relevant changes
- Reduces risk of unreviewed or low-quality code getting merged
- Improves accountability and knowledge-sharing across teams
- Creates a clear audit trail of who approved what
Where to Put the CODEOWNERS File
Create a file called CODEOWNERS in the .github/, root, or docs/ directory of your repository. If CODEOWNERS files exist in more than one of those locations, GitHub will search for them in that order and use the first one it finds.
The community standard — and best practice — is .github/CODEOWNERS. It keeps all repository configuration in one place.
# Create the file in the right location
mkdir -p .github
touch .github/CODEOWNERS
CODEOWNERS Syntax — Complete Reference
The CODEOWNERS file uses the same pattern syntax as .gitignore. Each line defines a pattern and one or more owners.
Basic Syntax
# Global owner — owns everything in the repo
* @username
# Own a specific directory
/src/ @org/backend-team
# Own a specific file
README.md @project-manager
# Own all files of a specific type
*.js @org/frontend-team
# Own a nested directory
/src/api/ @org/api-team
# Multiple owners — any one of them can approve
/infrastructure/ @devops-lead @org/devops-team
# Own files in any subdirectory (not just root)
docs/ @org/docs-team
Real-World Example — Monorepo Structure
# === Global Fallback ===
# Any file not matched below requires review from tech leads
* @org/tech-leads
# === Frontend ===
/frontend/ @org/frontend-team
/frontend/src/components/ @org/frontend-team @senior-frontend-dev
# === Backend ===
/backend/ @org/backend-team
/backend/api/ @org/api-team
# === Infrastructure & DevOps ===
/infrastructure/ @org/devops-team
/helm/ @org/devops-team
/.github/workflows/ @org/devops-team @org/tech-leads
# === Security-sensitive files ===
/backend/auth/ @security-lead @org/backend-team
*.env.example @security-lead
# === Documentation ===
/docs/ @org/docs-team
*.md @org/docs-team
# === Database ===
/migrations/ @db-admin @org/backend-team
Pattern Rules You Must Know
Last matching pattern wins — if a file matches multiple rules, the last one in the file takes precedence:
# This owns all .js files
*.js @org/frontend-team
# This overrides the above for API JS files specifically
/src/api/*.js @org/api-team
# Result: API JS files are owned by api-team, not frontend-team
Negation is not supported — unlike .gitignore, you cannot use ! to exclude files from ownership.
Directory patterns:
# Owns all files in /docs/ and subdirectories
/docs/ @org/docs-team
# Owns files named "docs" anywhere in the repo
docs @org/docs-team
# Owns all files in any directory named "docs"
docs/ @org/docs-team
Permissions — What You Must Get Right
This is where most CODEOWNERS setups break. Getting permissions wrong means reviews are requested from people who cannot actually approve — or worse, merges are silently allowed without proper review.
Required Permissions
The people you choose as code owners must have write permissions for the repository. When the code owner is a team, that team must be visible and it must have write permissions, even if all the individual members of the team already have write permissions directly, through organization membership, or through another team membership.
GitHub Permission Levels
| Role | Permissions | Can Be Code Owner? |
|---|---|---|
| Read | View, clone, comment | ❌ No |
| Triage | Manage issues and PRs, no code push | ❌ No |
| Write | Push commits, create branches, open PRs | ✅ Yes |
| Maintain | Manage settings, labels, branches | ✅ Yes (recommended) |
| Admin | Full access including repo deletion | ✅ Yes |
Best practice: Grant code owners at minimum Write access. In practice, Maintain is often needed — it allows merging on protected branches after approval.
The Most Common Permission Mistake
If you set a team as a code owner but individual members of that team do not have the necessary repository-level permissions, the CODEOWNERS setting will not function as expected and the team members will not be able to act on the PR in the capacity of a code owner.
Always verify:
- The team itself has Write or Maintain permission on the repository
- Individual team members are actually in the team
- The team is not empty
Enforcing Reviews With Branch Protection
By default, CODEOWNERS suggests reviewers but does not enforce anything. To make reviews mandatory before merging, you must set up branch protection rules.
Setting Up Branch Protection
- Go to Repository Settings → Branches → Branch Protection Rules
- Click Add Rule
- Set Branch name pattern to
main(or your default branch) - Enable these settings:
✅ Require a pull request before merging
✅ Require approvals (set to at least 1)
✅ Require review from Code Owners
✅ Dismiss stale pull request approvals when new commits are pushed
✅ Restrict who can push to matching branches
What Each Setting Does
Require review from Code Owners — the most important setting. When this is enabled, after a user or team with effective Write permission approves the pull request, merging is allowed. If the reviewer is not in the CODEOWNERS file or does not have effective Write permission, the merge is blocked.
Dismiss stale approvals — forces re-review if new commits are pushed after approval. Prevents the common pattern of getting approval then sneaking in changes.
Restrict pushes — prevents even admins from bypassing the review process by pushing directly to main.
Setting Up Teams for CODEOWNERS
Using teams instead of individual usernames is a critical best practice. Individual usernames create bottlenecks — if that person is on vacation, PRs pile up.
Creating a Team in GitHub
- Go to Organization Settings → Teams → New Team
- Name it clearly:
frontend-team,devops-team,api-team - Add members
- Set repository access to Write or Maintain
Using Teams in CODEOWNERS
# Individual — creates bottleneck risk
/backend/ @john-smith
# Team — better, any member can approve
/backend/ @org/backend-team
# Both — team gets notified, individual is backup
/backend/ @org/backend-team @senior-backend-dev
Team Hierarchy Pattern
For large organizations, nested teams work well:
# Parent team owns everything
* @org/engineering
# Child teams own their domains
/frontend/ @org/frontend-team
/backend/ @org/backend-team
/mobile/ @org/mobile-team
# Sub-teams own critical paths
/backend/payments/ @org/payments-team
/backend/auth/ @org/security-team
Common Mistakes and How to Fix Them
Mistake 1 — CODEOWNERS on Wrong Branch
By far the most common problem is when a pull request has an older version of the CODEOWNERS file on it. GitHub checks the CODEOWNERS file in the base branch of the pull request, not the head branch.
Fix: Always merge CODEOWNERS changes to your default branch first before expecting them to take effect on new PRs.
Mistake 2 — Team Has No Write Permission
You add @org/frontend-team to CODEOWNERS but the team only has Read access. GitHub shows an error in the CODEOWNERS file and reviews are not requested.
Fix: Go to Repository Settings → Collaborators & Teams → verify the team has Write or Maintain access.
Mistake 3 — Multiple CODEOWNERS Files
The CODEOWNERS file in .github/ takes precedence over the one in root, which takes precedence over docs/. Having files in multiple locations causes confusion about which one is active.
Fix: Use only .github/CODEOWNERS. Delete any CODEOWNERS files in root or docs.
Mistake 4 — Too Many Owners Per File
Assigning 10 people as owners of a file means 10 people get notified for every PR. Review fatigue sets in and approvals become rubber stamps.
Fix: Assign one team per path. Use sub-teams for critical paths that need stricter review.
Mistake 5 — No Global Fallback
If a file matches no pattern in CODEOWNERS, no review is requested for it — even with branch protection enabled.
Fix: Always add a global fallback as the first line:
# Global fallback — catches anything not matched below
* @org/tech-leads
Mistake 6 — File Size Over 3MB
CODEOWNERS files must be under 3MB in size. A CODEOWNERS file over this limit will not be loaded, which means code owner information is not shown and the appropriate code owners will not be requested to review changes.
Fix: Use wildcard patterns to consolidate multiple entries into a single entry.
Advanced Patterns
Per-Branch Ownership
Each CODEOWNERS file assigns the code owners for a single branch in the repository. You can assign different code owners for different branches.
# On main branch — senior team members
* @org/senior-engineers
# On release/* branches — release managers only
* @org/release-managers
Protecting CI/CD Workflows
# Anyone touching GitHub Actions workflows needs DevOps approval
/.github/workflows/ @org/devops-team
# Terraform changes need infrastructure team sign-off
/terraform/ @org/infrastructure-team
*.tf @org/infrastructure-team
Monorepo Pattern
The CODEOWNERS file is practically essential for managing large monorepos where different teams work in the same repository. A change to the mobile app’s code will only notify the mobile team, not the entire engineering organization.
# Monorepo ownership structure
/packages/mobile/ @org/mobile-team
/packages/web/ @org/web-team
/packages/api/ @org/api-team
/packages/shared/ @org/tech-leads
/packages/design-system/ @org/design-team @org/frontend-team
Security-Sensitive File Protection
# Security team must review any auth changes
/src/auth/ @security-lead @org/security-team
# Database migrations need DBA sign-off
/migrations/ @dba-team
# Dependency changes need security review
package.json @org/security-team
package-lock.json @org/security-team
go.sum @org/security-team
requirements.txt @org/security-team
Verifying Your CODEOWNERS Setup
Check for Errors
GitHub automatically validates your CODEOWNERS file. Go to: Repository → Insights → Code owners errors
Common errors shown here:
- Users or teams not found
- Missing Write permissions
- Invalid syntax patterns
Test It Works
- Create a new branch
- Modify a file covered by CODEOWNERS
- Open a pull request to main
- Verify the correct reviewers are automatically requested
- Verify merging is blocked until the required owners approve
Using GitHub CLI to Verify
# View CODEOWNERS file
gh api repos/{owner}/{repo}/contents/.github/CODEOWNERS
# Check team permissions
gh api orgs/{org}/teams/{team}/repos/{owner}/{repo}
# List team members
gh api orgs/{org}/teams/{team}/members
Full Best Practices Checklist
✅ Place CODEOWNERS in .github/ — not root or docs/
✅ Always add a global fallback (* @org/team) as the first line
✅ Use teams instead of individual usernames
✅ Give code owner teams Write or Maintain permissions
✅ Enable "Require review from Code Owners" in branch protection
✅ Enable "Dismiss stale approvals" to prevent approval smuggling
✅ Restrict direct pushes to main — no bypassing via push
✅ Use comments and sections to keep the file readable
✅ Keep ownership per path to one team — avoid review fatigue
✅ Protect CI/CD workflows and security-sensitive files explicitly
✅ Check Insights → Code owners errors regularly
✅ Review and update CODEOWNERS when team membership changes
✅ Test changes on a PR before considering setup complete
Complete Real-World CODEOWNERS Template
Copy this and adapt for your team:
# ================================================
# CODEOWNERS — devtoolhub/platform
# Last updated: May 2026
# ================================================
# === Global Fallback ===
# Anything not matched below requires tech lead approval
* @org/tech-leads
# === Frontend ===
/frontend/ @org/frontend-team
/frontend/src/components/ @org/frontend-team
*.css @org/frontend-team
*.scss @org/frontend-team
# === Backend ===
/backend/ @org/backend-team
/backend/api/ @org/api-team
# === Security Sensitive ===
/backend/auth/ @security-lead @org/backend-team
/backend/payments/ @security-lead @org/payments-team
*.env.example @security-lead
# === Infrastructure & DevOps ===
/infrastructure/ @org/devops-team
/terraform/ @org/devops-team
/helm/ @org/devops-team
/.github/workflows/ @org/devops-team @org/tech-leads
# === Database ===
/migrations/ @dba-lead @org/backend-team
# === Documentation ===
/docs/ @org/docs-team
*.md @org/docs-team
# === Dependencies ===
package.json @org/tech-leads @org/security-team
go.mod @org/tech-leads @org/security-team
requirements.txt @org/tech-leads @org/security-team
Frequently Asked Questions
Does CODEOWNERS work on private repositories? You can define code owners in public repositories with GitHub Free, and in public and private repositories with GitHub Pro, GitHub Team, GitHub Enterprise Cloud, and GitHub Enterprise Server.
What happens if a code owner is not available? The PR will be blocked until someone from the assigned team approves. This is why teams are better than individuals — any team member can unblock the PR.
Can I have different owners for different branches? Yes. Each branch can have its own CODEOWNERS file. The file on the base branch of a PR determines which owners are requested.
What if no pattern matches a changed file? No review is automatically requested. This is why a global fallback (* @org/team) is essential.
Can admins bypass CODEOWNERS? By default, admins can bypass branch protection rules. To prevent this, enable “Do not allow bypassing the above settings” in your branch protection rule.
Why are reviews being requested from the wrong people? Check which CODEOWNERS file is active (.github/ takes precedence), verify the last-matching-pattern rule, and check that team permissions are correctly set.
Can I use CODEOWNERS to protect GitHub Actions workflows? Yes — and you should. Add /.github/workflows/ @org/devops-team to prevent unauthorized workflow changes, which is a common supply chain attack vector.
Related Posts on DevToolHub
- ArgoCD vs Flux — Which GitOps Tool Should You Use?
- GitOps Explained — What It Is and Why It Matters
- Kubernetes RBAC Tutorial — Stop Giving Cluster-Admin to Everyone
- GitHub Actions CI/CD Pipeline — Complete Guide
- Docker vs Podman — Which Container Tool Should You Use?