Managing Code Review at Scale in Monorepos

Managing Code Review at Scale in Monorepos

Sagnik

Founder, autter.dev

3 min read

Your monorepo has 200 packages, 15 teams, and a shared infrastructure layer that everything depends on. A developer changes a utility function in the shared layer. The PR looks small — 12 lines changed. But that function is imported by 47 packages across 8 teams, and the behavioural change will break three of them in ways that won't show up until their next deployment.

This is the monorepo review problem: small changes can have outsized, invisible impact. And traditional code review tools have no way to surface that impact before merge.

Why monorepo review is different

In a polyrepo world, the blast radius of a change is contained to the repository it lives in. Change a function, run the tests in that repo, get a review from the team that owns it. Simple.

Monorepos collapse this isolation. A single PR can touch shared code that affects every team in the organisation. The challenges are specific:

  • Cross-package impact — a change to a shared utility can break consumers that aren't tested in the PR's CI scope
  • Ownership ambiguity — who reviews a change that touches packages owned by three different teams?
  • Inconsistent standards — different packages may have evolved different conventions, and a PR that crosses boundaries needs to respect both
  • Review routing — the right reviewer depends on which packages are affected, not just which files are changed
  • CI cost — running every package's test suite on every PR is prohibitively expensive; selective testing requires understanding impact

How autter solves monorepo review

autter is built with monorepo-scale codebases in mind. It understands package boundaries, dependency graphs, and cross-package impact — and uses this understanding to make review faster, safer, and more accurate.

Cross-package impact analysis

When a PR modifies shared code, autter traces the dependency graph to identify every affected consumer:

// autter impact analysis for PR #3847
// Changed: packages/shared/utils/format-currency.ts
//
// Direct consumers (7 packages):
//   packages/checkout/src/components/PriceDisplay.tsx
//   packages/invoicing/src/generators/pdf.ts
//   packages/reporting/src/charts/revenue.ts
//   packages/admin/src/views/billing.tsx
//   packages/api/src/routes/pricing.ts
//   packages/mobile/src/screens/Cart.tsx
//   packages/email/src/templates/receipt.ts
//
// Behavioural change detected:
//   format-currency() now rounds to 2 decimal places (was 0)
//   This changes output for all consumers.
//
// At-risk consumers (3 packages):
//   ⚠ packages/invoicing — tests compare exact string output
//   ⚠ packages/reporting — snapshot tests will break
//   ⚠ packages/api — API response format change (breaking)

This analysis happens in seconds — before any CI runs, before any reviewer looks at the PR.

Intelligent review routing

In a monorepo, the right reviewer isn't always the person who owns the files being changed — it's the person who owns the packages being affected. autter handles this automatically:

# autter.config.yml
monorepo:
  # Define package ownership
  ownership:
    - path: "packages/checkout/**"
      team: "@checkout-team"
    - path: "packages/invoicing/**"
      team: "@billing-team"
    - path: "packages/shared/**"
      team: "@platform-team"
 
  # Review routing rules
  routing:
    # Changes to shared code: require platform team + affected teams
    shared_code:
      paths: ["packages/shared/**"]
      require:
        - team: "@platform-team"           # owns the code
        - affected_teams: true             # auto-add affected package owners
 
    # Cross-package changes: require all affected teams
    cross_package:
      require:
        - affected_teams: true
        - min_reviewers: 1                 # per affected team

When the format-currency PR is opened, autter automatically requests reviews from @platform-team (owns the shared code), @billing-team (invoicing affected), @reporting-team (reporting affected), and @api-team (API affected).

Per-package standards

Different packages in a monorepo often have different conventions — the React frontend uses different patterns than the Go backend, which uses different patterns than the shared TypeScript utilities. autter supports per-package rule configuration:

# packages/checkout/.autter.yml (overrides root config)
rules:
  react:
    enforce_hooks_rules: true
    require_memo_for_list_items: true
  testing:
    require_rtl: true                      # React Testing Library
    min_coverage: 85%
 
# packages/api/.autter.yml
rules:
  api:
    require_openapi_update: true           # API changes must update the spec
    require_migration: true                # Schema changes need migrations
  testing:
    require_integration_tests: true
    min_coverage: 90%

Selective CI recommendations

Running every package's test suite on every PR is expensive. autter's impact analysis tells your CI exactly which packages need testing:

# GitHub Actions example
- name: Determine affected packages
  id: affected
  run: npx autter impact --format json > affected.json
 
- name: Test affected packages
  run: |
    PACKAGES=$(jq -r '.affected_packages[]' affected.json)
    for pkg in $PACKAGES; do
      npm test --workspace=$pkg
    done

This reduces CI time from "run everything" (45+ minutes in a large monorepo) to "run what's affected" (typically 5-15 minutes).

Change categorisation

autter categorises monorepo changes by their scope and risk:

CategoryDescriptionReview requirement
Package-localChanges contained within one packagePackage owner
Cross-packageChanges affecting multiple packagesAll affected owners
Shared infrastructureChanges to shared codePlatform team + affected owners
Build/configChanges to build tooling or configPlatform team
Breaking changeChanges that alter public APIsAll affected owners + architecture review

Results at scale

Teams running autter on monorepos with 100+ packages report:

MetricBefore autterAfter autter
Cross-package incidents per month4-70-1
Avg review routing accuracy~60%~95%
Time to identify impact scope30-60 min (manual)Under 2 min (automatic)
CI minutes per PR (avg)45 min12 min
Stale review requests30% of PRsUnder 5% of PRs

The biggest win is the incidents you don't have. A shared utility change that breaks a downstream package in production is expensive — in debugging time, in incident response, in customer trust. autter catches these before merge, every time.

Getting started

# Initialise autter with monorepo mode
npx autter init --monorepo
 
# autter will detect your package manager (npm/pnpm/yarn workspaces,
# Turborepo, Nx, Lerna) and build the dependency graph automatically
 
# Preview impact analysis for your current branch
npx autter impact --diff main...HEAD

Your monorepo is a force multiplier for your team. autter makes sure it doesn't become a liability.

14-day free trial

Ship with confidence,
starting today

autter is the merge gate built for the AI coding era. Try it free for 14 days — no credit card, no commitment, full access to every feature.

  • AI-powered code reviews on every PR
  • 40+ linters & custom checks
  • No credit card required

Stop shipping code you can't fully trust

autter is the merge gate built for the AI coding era. It catches what linters miss, flags what CI ignores, and gives your team the confidence to ship faster without the 2am surprises.

50,000+

Pull requests analysed every week, catching issues that passed CI but would have failed in production.

73%

Fewer production incidents from AI-generated code after teams adopt the autter merge gate.

<90s

Average time to first review. autter analyses your PR before a human reviewer even opens it.

Capt. Patch

Capt. Autter Patch

Online now

I've seen a lot of codebases. Most teams find out they needed Autter after a bad deploy. What does your PR review process look like right now?

Powered by Autter AI