GitHub CODEOWNERS: Complete Guide to Permissions & Best Practices (2026)

GitHub CODEOWNERS & Permissions

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

RolePermissionsCan Be Code Owner?
ReadView, clone, comment❌ No
TriageManage issues and PRs, no code push❌ No
WritePush commits, create branches, open PRs✅ Yes
MaintainManage settings, labels, branches✅ Yes (recommended)
AdminFull 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:

  1. The team itself has Write or Maintain permission on the repository
  2. Individual team members are actually in the team
  3. 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

  1. Go to Repository Settings → Branches → Branch Protection Rules
  2. Click Add Rule
  3. Set Branch name pattern to main (or your default branch)
  4. 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

  1. Go to Organization Settings → Teams → New Team
  2. Name it clearly: frontend-team, devops-team, api-team
  3. Add members
  4. 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

  1. Create a new branch
  2. Modify a file covered by CODEOWNERS
  3. Open a pull request to main
  4. Verify the correct reviewers are automatically requested
  5. 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

Official Resources

Uncategorized