One of the most impactful architectural decisions a company makes is how to organize code across projects. Do you put everything in one repository (monorepo) or split it into multiple repositories (multi-repo)? This choice cascades — it affects CI/CD, deployment, shared code management, testing, and developer experience.
I've worked at companies organized both ways. Neither is objectively correct. But understanding the trade-offs helps you choose what's right for your context.
Monorepo: Everything in One Repository
A monorepo contains multiple projects or packages in a single Git repository. Google, Meta, Twitter, and Microsoft all use monorepos for their primary codebases.
/my-company-monorepo
/apps
/api
/web
/mobile
/admin
/packages
/ui-components
/auth
/database-schemas
/shared-types
/libs
/utils
Advantages:
- Shared code is easy: Need a shared utility? Add it to /libs. Every package automatically gets access. No version management complexity.
- Unified versioning: One version number. All projects are always at the same version. No surprises from incompatible versions.
- Atomic commits: Change API and web simultaneously in one commit. No "these two changes need to ship together" complexity.
- Refactoring across projects: Need to move a function? Refactor tools work across the entire monorepo. One refactoring session, one commit.
- Consistent practices: One linter, one formatter, one CI pipeline. No "why does this project use ESLint but the other uses StandardJS?"
Disadvantages:
- Repository size: Over time, monorepos get large. Git operations slow down. Cloning takes longer.
- CI complexity: Determine which tests to run. If you change a shared package, do you rebuild everything? Do you re-test every project? Build times can get long.
- Permission and access control: Can't restrict a developer to only seeing one project's code. Some organizations require different teams to have different access levels.
- Deployment granularity: Multiple projects can't deploy independently without infrastructure to detect which parts changed.
- Team friction: Changes to shared code affect everyone. Requires communication and coordination.
Multi-Repo: Separate Repository Per Project
Each project has its own repository. Api lives in /company/api-repo, web lives in /company/web-repo, etc. Shared code lives in separate packages.
/company
/api-repo
/web-repo
/mobile-repo
/admin-repo
/ui-components-repo
/auth-repo
Advantages:
- Independent deployments: Each project deploys independently. Fix a bug in one, ship immediately. Don't block others.
- Repository size: Smaller repositories mean faster clones, faster Git operations, faster local development.
- Permission management: Can restrict access. Frontend team doesn't see backend code.
- Fast CI: Each project runs its own CI. No complex logic determining what to test.
- Clear boundaries: Each team owns their project explicitly. No surprises from changes elsewhere.
Disadvantages:
- Shared code management is complex: A shared utility requires its own repository. Managing versions, deprecations, and compatibility is overhead.
- Version management: API v1.2, Web v2.1, Mobile v0.5. Incompatibilities happen. Someone uses an old version of a package and doesn't get security fixes.
- Cross-project refactoring is painful: Move a function and you have to update imports in 3 repositories. Create a PR in each. Coordinate releases.
- Duplicated logic: Without a shared package, teams re-implement the same logic. Someone writes a date utility in API, someone else writes one for web. Code duplication and inconsistency.
- Atomic commits are impossible: Breaking changes to a shared library require releasing, updating all consumers, and coordinating releases across projects.
Choosing Between Them
Use a monorepo when:
- You have significant shared code between projects
- You need to coordinate changes across projects
- You have a small to medium-sized team (under 50 engineers)
- You value refactoring and code quality
- You can invest in infrastructure (build caching, smart testing)
Use multi-repo when:
- Projects are truly independent with minimal shared code
- Teams are autonomous and rarely coordinate
- You have large teams where permission management is critical
- You want absolute independence between projects
- Repository size and Git performance are constraints
Practical Monorepo Tools
If you choose monorepo, tools make the complexity manageable:
- Nx (TypeScript/JavaScript): Build system that understands project dependencies, caches builds, and runs only affected tests.
- Turborepo: Fast monorepo build system. Good for JavaScript/TypeScript projects.
- Bazel: Google's build system. Incredibly powerful but steep learning curve.
- Git submodules/subtrees: Poor solution. Avoid if possible.
Whichever you choose, commit to it. Switching from multi-repo to monorepo (or vice versa) is painful and expensive. Choose carefully based on your team's needs, not hype.