Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXVIII · Monorepo vs Multi-RepoArchitecture

Multi-repo architecture — one repository per service or project

Advanced⏱ ~23 mingit

What you'll learn

  • Describe the physical shape of a multi-repo and what it does to the working tree
  • Identify the ownership, release-cadence, and blocker patterns that keep a multi-repo tractable
  • Recognise the cost of cross-repo changes and the patterns that mitigate them
  • Recall the published examples at Netflix, Amazon, and smaller teams and the scale each operates at

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A multi-repo is many repositories where each one owns a single service or project. The unit of merge is the repository; the unit of release is the tagged commit; the unit of ownership is the repository-level CODEOWNERS. The whole model rests on the assumption that the team can solve the cross-repo problem: given a change that touches two services, how do the two repositories agree on what landed first, who reviewed it, and which version of each is in production?

The physical shape

A multi-repo is many .git directories, many HEADs, many branches, and many working trees. Each repository holds one service or project: a Terraform module, an Ansible role, a Kubernetes manifest set, a backend application. The unit of merge is the repository’s trunk; the unit of build is the repository’s pipeline; the unit of ownership is the repository-level CODEOWNERS plus the team that owns the repository.

flowchart LR
    subgraph MR["Multi-repo fleet"]
        R1["payments-api"]
        R2["billing-worker"]
        R3["identity-svc"]
        R4["payments-terraform"]
        R5["payments-ansible"]
    end
    MR --> CR[Cross-repo glue: pinned references]
    MR --> D[Distributed CODEOWNERS]
    MR --> BC[Independent branch protection]

The benefit is that each repository has its own trunk, its own blast radius, its own release cadence, and its own reviewer list. The cost is that a logical change that touches two services is two pull requests, two reviews, two merges, and two deploys, and the team’s release process is the only glue that keeps them in sync.

What the cross-repo glue has to do

A multi-repo without a cross-repo glue is a fleet of uncoordinated trunks. The glue is usually one of:

  • Versioned references. A consumer repository declares a pinned tag of the producer repository’s module, and the build pins the digest. The two trunks ship at their own speed; the consumer picks up the new version explicitly.
  • Shared CI matrix. A central pipeline builds the repositories in dependency order, and the merge of one trunk is gated on the green of the dependent.
  • Submodule / subtrees. A parent repository embeds a pinned reference to a child repository, and the parent’s clone pulls the child at the pinned commit.

The pattern is the same: the cross-repo glue is a first-class artifact, not a side effect of CI. Without the glue, a change that lands in repository A but not in repository B leaves the system in a broken intermediate state.

What the working tree has to do

A multi-repo’s working tree is one repository at a time. The optimisations are different from the monorepo:

REPO_URL="git@github.com:example/payments-api.git"

git clone --depth 1 "$REPO_URL"
cd payments-api
git ls-files | wc -l

The --depth 1 flag tells the server to omit history older than the most recent commit. For a repository that is owned by a single team and ships independently, the cheap clone is often the right default; the history is still on the server, and the engineer can fetch deeper when they need it.

What the published examples look like

The large-scale multi-repo examples are not aspirational; they are operational:

  • Netflix. Each microservice is its own repository, with its own trunk, its own CI pipeline, and its own release cadence. The stated motivation is the independent release cadence of hundreds of services.
  • Amazon. Each team owns its services as separate repositories, with the team itself as the unit of code ownership. The stated motivation is the team boundary being the unit of release.
  • Smaller teams. A team of three to five engineers often finds the multi-repo cheaper than the monorepo because the blast radius per repository is small and the cross-repo glue is a hand-maintained file.

The trade-off published in all three is the same: the team pays the cost of cross-repo coordination in exchange for the independence of each repository’s trunk.

Production discipline

  1. Treat the repository boundary as the unit of blast radius. High-blast-radius assets (network, IAM, secrets) belong in their own repository, not bundled with application code.
  2. Pin every cross-repo reference. A versioned reference is auditable; a git pull of latest is not.
  3. Use --depth 1 for cheap clones, but be ready to fetch deeper. The engineer who needs to bisect the history needs the full history.
  4. Verify the working tree with git ls-files | wc -l. A 200,000-file working tree is a working tree that needs a sparse-checkout, not a multi-repo.

Cross-course references

  • Linux for Production Sysadmins - Part XXVI (RepoLayout) covers the filesystem analogue: per-service trees versus a single root tree.
  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) covers the role-based layout of a single-tool Ansible repository, and the cost of cross-role coordination.
  • Terraform for Production Sysadmins - Part IX (State) covers why Terraform state is the strongest argument for keeping Terraform in its own repository, even inside a multi-repo fleet.

Quiz

Knowledge check · 4 questions

  1. Q1. A team operates a multi-repo fleet of 200 microservices. A change to the deployment pipeline needs to land in two repositories that depend on each other. What is the cross-repo glue that prevents the fleet from drifting?

  2. Q2. In a multi-repo, the blast radius of a misconfigured CODEOWNERS grant is scoped to the single repository the CODEOWNERS file belongs to.

  3. Q3. Name the three patterns that act as cross-repo glue in a multi-repo fleet, and the one that is most common at small team scale.

  4. Q4. Recommend a working-tree setup for an engineer who needs to bisect a bug across a multi-repo fleet, and verify the setup with `git ls-files`.

    An engineer is debugging a production bug that spans three repositories: `payments-api`, `billing-worker`, and `payments-terraform`. The engineer needs to check out the same tagged commit of each repository, bisect the history of one of them, and verify the working tree of each.

Passing score: 75%. Answers are checked in this browser.