Where code lives is a design decision: it changes how teams share code, how CI runs and how releases happen.
flowchart LR
subgraph MR["Mono-repo"]
R["one repo: services/cart, services/orders, libs/auth"] --> CI["CI: build only what changed"]
end
subgraph MU["Multi-repo"]
R1["cart repo"] --> C1["cart CI"]
R2["orders repo"] --> C2["orders CI"]
R3["auth-lib repo"] --> PKG["package registry"]
PKG --> R1
PKG --> R2
end
%% step R: One repository holds every service and shared library, with one history.
%% step CI: Path filters or build tools decide which services to rebuild for each commit.
%% step R1: In a multi-repo, each service has its own repository, permissions and pipeline.
%% step PKG: Shared code is published as versioned packages and consumed like any dependency.
Mono-repo
Pros: unified tooling and standards; easy code sharing and atomic changes across services ("rename this API and all callers in one commit"); one place to search.
Cons: repository grows large (slower clone, needs sparse checkout or partial clone); CI must be smart about what to build; permissions are coarser; one broken main branch affects everyone.
Multi-repo
Pros: simple per-repo management; clear ownership and permissions; teams release independently and in parallel.
Cons: code duplication or a package-versioning burden for shared libraries; cross-service changes need several pull requests in the right order; integration problems appear late.
CI/CD consequences
| Concern | Mono-repo | Multi-repo |
|---|---|---|
| Trigger | Path filters (services/cart/**) or build graphs (Bazel, Nx, Turborepo) |
Every push to that repo |
| Shared library change | One PR, all callers tested together | Publish new version, bump each consumer |
| Clone time | Use --filter=blob:none and sparse checkout |
Small repos, fast clones |
| Ownership | CODEOWNERS per folder | Repo-level permissions |
Choosing
Many companies run a hybrid: one repo per product or domain, platform libraries in their own repo. Pick what keeps changes small and releases independent for your team structure.
Traps: a mono-repo where every commit builds and deploys every service; a multi-repo where ten repos must be released in lockstep (that is a distributed monolith again); copying shared code instead of versioning it.