LogoMasst Docs

Monorepo vs Multi-repo

A comprehensive guide to repository strategies - choosing between monorepo and multi-repo architectures for your projects

What is a Monorepo?

A Monorepo (monolithic repository) is a single repository that contains multiple projects, applications, or packages. All code lives in one place, with shared tooling, dependencies, and configurations.

Example: Google, Meta, and Microsoft use monorepos containing thousands of projects and millions of lines of code.

What is Multi-repo?

A Multi-repo (polyrepo) strategy uses separate repositories for each project, service, or package. Each repo is independently versioned, deployed, and maintained.

Example: Netflix uses separate repositories for each microservice, with clear ownership boundaries.


Architecture Comparison

AspectMonorepoMulti-repo
Code LocationSingle repositorySeparate repositories
DependenciesShared, always in syncVersioned via package manager
ToolingUnified build/test/lintPer-repo configuration
VisibilityEveryone sees all codeAccess controlled per repo
Atomic ChangesCross-project changes in one commitRequires coordinated PRs
CI/CDComplex (need smart filtering)Simple per-repo pipelines

Monorepo Deep Dive

Structure

my-company/
├── apps/
│   ├── web/                 # Main web application
│   ├── mobile/              # React Native app
│   └── admin-dashboard/     # Internal admin tool
├── packages/
│   ├── ui/                  # Shared UI components
│   ├── utils/               # Common utilities
│   ├── config/              # Shared configurations
│   └── types/               # TypeScript definitions
├── services/
│   ├── api-gateway/         # API Gateway service
│   ├── user-service/        # User management
│   └── payment-service/     # Payment processing
├── tools/
│   └── scripts/             # Build and deployment scripts
├── package.json             # Root package.json
├── turbo.json               # Turborepo config
└── nx.json                  # Nx config (alternative)

Key Benefits

1. Atomic Changes

Make cross-project changes in a single commit.

# One commit updates everything
feat: add dark mode support

- packages/ui: Add theme prop to Button
- apps/web: Implement theme toggle
- services/api: Add user preference endpoint

2. Shared Dependencies

Single source of truth for all dependencies.

// Root package.json
{
  "dependencies": {
    "react": "^18.2.0",
    "typescript": "^5.0.0"
  }
}

No version conflicts. Update once, applies everywhere.

3. Code Reuse

Import shared code directly without publishing packages.

// apps/web/src/components/Header.tsx
import { Button } from '@company/ui';
import { formatDate } from '@company/utils';
import type { User } from '@company/types';

4. Unified Tooling

One configuration for linting, testing, and building.

// Root eslint.config.js applies to all projects
// Root tsconfig.json shared across all TypeScript code
// Single CI/CD pipeline with smart caching

Monorepo Tooling

ToolBest ForKey Features
TurborepoJavaScript/TypeScript projectsFast, simple, Vercel integration
NxEnterprise monoreposPlugins, generators, graph visualization
BazelLarge-scale, multi-languageHermetic builds, Google-proven
LernaPublishing npm packagesVersioning, changelog generation
pnpmEfficient package managementStrict dependencies, disk efficient

Task Orchestration

// turbo.json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    },
    "lint": {
      "outputs": []
    }
  }
}

Affected Detection

Only build/test what changed:

# Turborepo
npx turbo run build --filter=...[origin/main]

# Nx
npx nx affected --target=build --base=origin/main

Multi-repo Deep Dive

Structure

github.com/my-company/
├── frontend-web/           # Main web application
├── frontend-mobile/        # React Native app
├── backend-api-gateway/    # API Gateway
├── service-users/          # User service
├── service-payments/       # Payment service
├── lib-ui-components/      # Shared UI (npm package)
├── lib-common-utils/       # Shared utilities (npm package)
└── infra-terraform/        # Infrastructure as code

Key Benefits

1. Clear Ownership

Each repo has defined owners and access controls.

# CODEOWNERS in service-payments/
* @payments-team
/src/fraud/ @security-team

2. Independent Lifecycles

Each service versions and deploys independently.

3. Simpler CI/CD

Each repo has its own straightforward pipeline.

# .github/workflows/ci.yml (per repo)
name: CI
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test
      - run: npm run build

4. Technology Flexibility

Each repo can use different languages, frameworks, and tools.

service-users/       → Go + PostgreSQL
service-payments/    → Java + Spring Boot
service-analytics/   → Python + FastAPI
frontend-web/        → React + TypeScript

Multi-repo Challenges & Solutions

Challenge 1: Dependency Management

Solutions:

  • Semantic versioning with strict ranges
  • Automated dependency updates (Dependabot, Renovate)
  • Regular synchronization releases

Challenge 2: Cross-repo Changes

# Updating shared library requires multiple PRs
1. PR to lib-ui-components (bump version)
2. Publish new npm version
3. PR to frontend-web (update dependency)
4. PR to frontend-mobile (update dependency)
5. PR to admin-dashboard (update dependency)

Solutions:

  • Automation scripts for multi-repo updates
  • Codemods for breaking changes
  • Versioned contracts (API specs, TypeScript types)

Challenge 3: Code Discovery

Solutions:

  • Central documentation (Backstage, wiki)
  • Consistent naming conventions
  • Service catalog with ownership info

Hybrid Approaches

Many organizations use a combination of both strategies.

Common Patterns

PatternDescription
Frontend MonorepoAll frontend apps + shared UI in one repo
Backend Multi-repoEach microservice in its own repo
Shared Libs MonorepoTypes, contracts, and configs in dedicated monorepo
Team MonoreposEach team owns a monorepo for their domain

Decision Framework

Choose Monorepo When

  • ✅ High code sharing between projects
  • ✅ Frequent cross-project changes
  • ✅ Single technology stack
  • ✅ Small to medium team size
  • ✅ Strong DevOps capabilities for tooling

Choose Multi-repo When

  • ✅ Clear service boundaries with minimal sharing
  • ✅ Teams need strong autonomy
  • ✅ Different technology stacks per service
  • ✅ Strict access control requirements
  • ✅ Simple CI/CD is a priority

Migration Strategies

Monorepo → Multi-repo

# Extract service to new repo
1. Create new repository
2. Copy service code with git history (git filter-branch)
3. Update CI/CD for new repo
4. Remove code from monorepo
5. Update dependencies to use published packages

Multi-repo → Monorepo

# Merge repos while preserving history
1. Create monorepo structure
2. Use git subtree or custom scripts to import repos
3. Update import paths
4. Consolidate configurations
5. Set up monorepo tooling (Nx, Turborepo)

Summary Table

FactorMonorepoMulti-repo
Code SharingEasy, direct importsVia versioned packages
Atomic ChangesSingle commit across projectsCoordinated PRs
CI/CD ComplexityHigh (needs smart tooling)Low (simple per-repo)
OnboardingClone once, access allClone multiple repos
Access ControlHarder to restrictFine-grained per repo
Tooling RequiredNx, Turborepo, BazelStandard git workflows
ScalingNeeds optimization at scaleScales naturally
Dependency SyncAlways in syncVersion management overhead

Interview Tips

  • Know the trade-offs: Neither approach is universally better—it depends on team size, code sharing needs, and organizational structure.
  • Discuss tooling: Mention Nx, Turborepo, or Bazel for monorepos; discuss versioning strategies for multi-repo.
  • Real-world examples: Google, Meta, Microsoft use monorepos; Netflix, Amazon prefer multi-repo (for microservices).
  • Hybrid is common: Many companies use both—monorepo for related projects, multi-repo for independent services.
  • Scaling challenges: Discuss how monorepos need affected detection and remote caching at scale.
  • Connect to microservices: Multi-repo aligns well with microservices; monorepo works better for shared libraries and related apps.

Repository strategy is a foundational architectural decision. Choose based on your team's collaboration patterns, code sharing needs, and operational capabilities—not industry trends.