Skip to content

Monorepos with Git: Strategies, Tools & Tradeoffs

DodaTech Updated 2026-06-22 5 min read

In this tutorial, you'll learn about Monorepos with Git: Strategies, Tools & Tradeoffs. We cover key concepts, practical examples, and best practices.

A monorepo stores multiple related projects in one Git repository, simplifying dependency management and enabling cross-project refactoring at scale.

In this tutorial, you'll learn monorepo strategies for managing multiple projects in a single Git repository. Monorepos simplify dependency management, enable cross-project refactoring, and streamline CI/CD — but they also introduce challenges with scale, code ownership, and git performance. By the end, you'll know how to structure, build, and maintain a monorepo effectively.

flowchart TD
  subgraph MonorepoStructure
    A[packages/] --> B[web-app]
    A --> C[mobile-app]
    A --> D[shared-lib]
    A --> E[api-server]
    B --> F[package.json]
    C --> F
    D --> F
  end
  subgraph CI
    G[Affected: web-app] --> H[Test web-app only]
    G --> I[Build web-app only]
  end

Why Monorepos?

Monorepos solve several problems that arise with multiple repositories:

  1. Shared code: A bugfix in a shared library is applied in one commit across all projects
  2. Atomic commits: A feature that touches both frontend and backend is a single commit
  3. Unified CI/CD: One pipeline configuration, one build process
  4. Simplified dependency management: No version mismatch between packages
  5. Cross-team refactoring: Rename a shared interface and fix all consumers in one PR

Monorepo Structure

A typical monorepo layout:

my-monorepo/
├── packages/
│   ├── web-app/
│   │   ├── src/
│   │   └── package.json
│   ├── mobile-app/
│   │   ├── src/
│   │   └── package.json
│   └── shared-lib/
│       ├── src/
│       └── package.json
├── tools/
│   └── scripts/
├── package.json
├── turbo.json
└── .gitignore

Dependency Management

Use workspaces to manage shared dependencies:

// root package.json
{
  "workspaces": [
    "packages/*]
  ]
}

Install dependencies once at the root — all packages share them:

npm install

Expected output:

added 1250 packages in 15s

Build Tools for Monorepos

Turborepo

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

Run commands across packages:

npx turbo run test --filter=web-app

Nx

npx nx affected:test --base=main

Nx calculates which projects were affected by changes since main and only runs tasks on those.

Git Strategies for Monorepos

Use sparse checkout to work with only the packages you need:

git clone --filter=blob:none monorepo
git sparse-checkout set packages/web-app packages/shared-lib

This reduces clone time and disk usage significantly for large monorepos.

CODEOWNERS for Access Control

# .github/CODEOWNERS
/packages/web-app/    @team-web
/packages/api-server/ @team-api
/shared-lib/          @team-core

Pull requests touching these paths automatically request reviews from the respective teams.

Comparison: Monorepo vs Polyrepo

Aspect Monorepo Polyrepo
Dependency updates Single version across projects Each repo manages own deps
Cross-project refactoring One commit across all Multiple PRs across repos
CI/CD complexity Needs affected-project detection Simple per-repo pipelines
Code ownership Needs CODEOWNERS Natural by repo
Git performance Degrades with size Stays constant
Tooling support Specialized tools needed Standard Git workflow
Atomic changes Yes No

Common Errors

Error Cause Fix
npm ERR! ERESOLVE Conflicting dependencies across packages Use resolutions or upgrade deps
Too many open files on clone Large monorepo Use shallow clone or sparse checkout
Input/output error on git status Repository too large Enable feature.manyFiles in Git config
CI runs all tests unnecessarily No affected-project detection Use Nx, Turborepo, or lerna changed
Package not found in workspace Missing workspace config Check package.json workspaces field
Merge conflicts in package-lock.json Multiple teams modifying deps Use pnpm with strict lockfile
Pre-commit hook too slow Hook scans entire repo Scope hook to changed files only
Git blame shows reformatting Global formatting changes Use .git-blame-ignore-revs

Practice Questions

What is a monorepo?

A monorepo is a single Git repository that contains multiple distinct projects. Unlike polyrepo (one repo per project), a monorepo shares tooling, dependencies, and CI/CD configuration across all projects, enabling atomic cross-project changes.

How do I manage dependencies in a monorepo?

Use package manager workspaces (npm workspaces, yarn workspaces, or pnpm workspaces). The root package.json defines the workspace pattern, and all sub-packages share a single lock file and node_modules structure.

What is affected-project detection and why is it important?

Affected-project detection determines which packages changed since a base commit (usually main). Only affected packages and their dependents are built and tested. This is critical for monorepo CI/CD because building the entire repository is too slow and wasteful.

Should I use a monorepo for my startup?

For small teams (under 10 people) with 2-3 projects, a monorepo simplifies sharing code and managing dependencies. As the team and project count grow, invest in monorepo tooling (Nx, Turborepo) to avoid slowdowns.

What is sparse checkout and when should I use it?

Sparse checkout limits which files Git checks out from the repository. Use it in large monorepos where each developer only needs a subset of packages. Combined with --filter=blob:none, it drastically reduces clone time and disk usage

Challenge

Set up a monorepo with three packages: a shared library, a web application, and a CLI tool. Configure npm workspaces. Add Turborepo with build, lint, and test tasks. Implement CODEOWNERS so different teams own different packages. Demonstrate an atomic change across the shared library and the web app in a single commit.

Real-World Task

Migrate a project from three separate Git repositories into a single monorepo. Preserve the commit history of each repository using git subtree or git filter-repo. Set up Nx to detect affected projects and run only relevant CI pipelines. Configure sparse checkout for developers who only need specific packages. This monorepo migration approach is used at DodaTech for consolidating tools like DodaZIP and Durga Antivirus Pro components.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro