---
title: "Code Governance"
description: "Create CODEOWNERS file, assign teams to packages and apps, configure GitHub branch protection, and ensure proper code review workflows."
canonical_url: "https://vercel.com/academy/production-monorepos/code-governance"
md_url: "https://vercel.com/academy/production-monorepos/code-governance.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-04-12T07:56:16.387Z"
content_type: "lesson"
course: "production-monorepos"
course_title: "Production Monorepos with Turborepo"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Code Governance

# Code governance

In large monorepos, teams need clear ownership boundaries. Without governance, anyone can change critical packages, reviews get routed to the wrong people, and quality suffers. CODEOWNERS assigns clear team responsibility, while GitHub branch protection enforces review requirements before code ships.

## Outcome

Set up code ownership rules and branch protection for team accountability and code quality.

## Fast track

1. Create CODEOWNERS file with team assignments
2. Configure ESLint module boundaries
3. Test boundary enforcement
4. Verify PR review requirements

## Hands-on exercise 9.3

### 1. Create CODEOWNERS file

Create `.github/CODEOWNERS`:

```plaintext title=".github/CODEOWNERS"
# TODO: Add ownership rules following this pattern:
# - default owner (root files)
# - packages ownership (UI team, config team, utils team)
# - apps ownership (web team, app team, docs team)
# - CI/CD ownership (devops team)
#
# Format: <file-pattern> <@github-username-or-team>
```

Solution

```plaintext title=".github/CODEOWNERS"
# Default owner for all files
* @geniusgarage/leads

# Package ownership
/packages/ui/ @geniusgarage/frontend-team
/packages/typescript-config/ @geniusgarage/platform-team
/packages/eslint-config/ @geniusgarage/platform-team
/packages/utils/ @geniusgarage/platform-team

# App ownership
/apps/web/ @geniusgarage/marketing-team
/apps/snippet-manager/ @geniusgarage/product-team
/apps/docs/ @geniusgarage/docs-team

# Infrastructure
/.github/ @geniusgarage/devops-team
/turbo.json @geniusgarage/platform-team
/package.json @geniusgarage/platform-team
```

### 2. Understand CODEOWNERS patterns

**Pattern matching:**

```
/apps/web/             # Exact directory
*.md                   # All markdown files
/packages/*/src/       # All package src directories
turbo.json             # Specific file
```

**Multiple owners:**

```
/packages/ui/ @geniusgarage/frontend-team @geniusgarage/design-team
```

Both teams must approve changes!

**Override patterns:**

```
* @geniusgarage/leads
/packages/ui/ @geniusgarage/frontend-team
/packages/ui/src/button.tsx @geniusgarage/design-system-lead
```

More specific patterns override general ones.

### 3. Test CODEOWNERS

Create a PR that changes `packages/ui/src/button.tsx`:

```tsx title="packages/ui/src/button.tsx" {5}
export function Button({ children, variant = 'primary', onClick }: ButtonProps) {
  const variants = {
    primary: 'bg-blue-500 text-white hover:bg-blue-600',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
    success: 'bg-green-500 text-white hover:bg-green-600',  // New variant
  }

  return (
    <button onClick={onClick} className={`${variants[variant]} px-4 py-2 rounded`}>
      {children}
    </button>
  )
}
```

GitHub will:

1. **Auto-request review** from `@geniusgarage/frontend-team`
2. **Block merge** until team approves
3. **Show required reviewers** on PR

CODEOWNERS in action!

\*\*Note: Architectural Boundaries\*\*

While CODEOWNERS enforces team ownership, you may also want to enforce architectural boundaries (e.g., prevent apps from importing other apps).

Turborepo is developing a native boundary enforcement feature that will be more powerful and integrated than third-party ESLint plugins. This feature is currently in alpha and will provide first-class support for:

- Package-to-package import rules
- Public API enforcement
- Cross-app isolation
- Type-safe boundaries

For now, use TypeScript path aliases and clear documentation to guide developers on import patterns. Watch the [Turborepo roadmap](https://github.com/vercel/turborepo/discussions) for updates on native boundary support.

## GitHub branch protection

Combine CODEOWNERS with branch protection:

### 1. Enable branch protection rules

In GitHub repository settings:

1. **Settings** → **Branches** → **Add rule**
2. **Branch name pattern:** `main`
3. **Enable:**
   - ✅ Require a pull request before merging
   - ✅ Require approvals (1)
   - ✅ Require review from Code Owners
   - ✅ Require status checks (CI)
   - ✅ Require branches to be up to date

### 2. Test protection

Create PR changing `packages/ui/`:

1. **Auto-requested reviewer:** `@geniusgarage/frontend-team`
2. **Status checks:** CI must pass
3. **Merge blocked** until review approval

No one can bypass team ownership!

## Benefits

**Before Governance:**

- Anyone changes any package
- No review requirements
- Inconsistent code quality
- No clear team ownership

**With Governance:**

- CODEOWNERS enforces team reviews
- GitHub blocks merges without approval
- Required CI checks before merge
- Clear team ownership and accountability

**For 10-person team:**

- 50% fewer bugs from unauthorized changes
- Faster PR reviews (right team, first time)
- Clearer ownership and responsibility
- Reduced context-switching for reviewers

## Governance best practices

### Start small, expand gradually

```plaintext
# Phase 1: High-level ownership
/apps/ @geniusgarage/snippet-manager-team
/packages/ @geniusgarage/platform-team

# Phase 2: Team-specific ownership
/apps/web/ @geniusgarage/marketing-team
/apps/snippet-manager/ @geniusgarage/product-team

# Phase 3: Component-level ownership
/packages/ui/src/button.tsx @geniusgarage/design-system-lead
```

### Document ownership decisions

Add comments to CODEOWNERS explaining team responsibilities:

```plaintext title=".github/CODEOWNERS"
# Design system components - reviewed by design team for consistency
/packages/ui/ @geniusgarage/frontend-team @geniusgarage/design-team

# Platform packages - critical infrastructure requiring platform team review
/packages/typescript-config/ @geniusgarage/platform-team
/packages/eslint-config/ @geniusgarage/platform-team

# App-specific code - product teams own their apps
/apps/web/ @geniusgarage/marketing-team
/apps/snippet-manager/ @geniusgarage/product-team
```

Documentation helps new team members understand ownership rationale!

### Regular ownership audits

Quarterly review:

- Are teams still aligned with CODEOWNERS?
- Has team structure changed?
- Are reviews getting to the right people?
- Should any ownership be more granular?

Adjust CODEOWNERS based on team structure and product evolution.

## Done-when

Verify code governance:

- [ ] Created `.github/CODEOWNERS` file
- [ ] Assigned teams to packages and apps
- [ ] Documented ownership rationale with comments
- [ ] Created PR changing owned package
- [ ] Verified CODEOWNERS auto-requested correct team
- [ ] Enabled branch protection rules (require review from code owners)
- [ ] Tested that merge is blocked without approval
- [ ] Understood how CODEOWNERS integrates with CI
- [ ] Set up quarterly ownership audit process

## What's Next

**Course complete!** 🎉

You've built a production-ready Turborepo monorepo with:

- Multiple apps sharing packages
- Intelligent caching and filtering
- CI/CD with GitHub Actions
- Environment variable validation
- Comprehensive testing
- Code generators
- Automated versioning
- Team governance

**Next steps:**

1. **Deploy to production** - All 3 apps to Vercel
2. **Add more apps** - Scale to 5+ apps with same patterns
3. **Publish packages** - Use Changesets to publish to npm
4. **Expand governance** - Add more teams and boundaries
5. **Monitor performance** - Track cache hit rates and build times

**Resources:**

- [Turborepo Docs](https://turbo.build/repo/docs)
- [Changesets Docs](https://github.com/changesets/changesets)
- [CODEOWNERS Syntax](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners)
- [GitHub Branch Protection](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches)

Keep building!


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
