Topic 6.4
Submodules & Monorepos: When Each Makes Sense
In one line
A submodule embeds one Git repository inside another at a specific pinned commit; a monorepo instead keeps multiple projects together in one single repository — two opposite answers to 'how do I manage related codebases,' each with real trade-offs.
Think of it like this
A submodule is like referencing a specific, exact edition of a reference book inside your own book's bibliography — you point at precisely one fixed version, and updating your reference is a deliberate, separate act. A monorepo is like binding several related books into one single volume from the start — one shared cover, one shared index, everything physically together.
Key ideas
- 01
A GIT SUBMODULE (
git submodule add <url> <path>) embeds another repository inside yours at a specific PATH, pinned to one exact commit — your repository records which commit of the submodule it depends on, but the submodule's own history and commits remain entirely separate, in their own repository. - 02
Cloning a repository with submodules requires an extra step —
git clone --recurse-submodules <url>(orgit submodule update --init --recursiveafter a plain clone) — since a normal clone does NOT automatically download submodule content, only the pointer recording which commit it's pinned to. Forgetting this step is a genuinely common source of 'why are these folders empty' confusion. - 03
A MONOREPO takes the opposite approach entirely: multiple distinct projects (perhaps a frontend, a backend, and a shared library) live together in ONE single repository, sharing one commit history, one set of branches, and typically one set of CI pipelines — a single commit CAN atomically change code across multiple projects at once, which is impossible by definition with separate repositories (submoduled or not).
- 04
Submodules genuinely fit when you need to depend on an EXTERNAL project's exact, specific version (a shared library maintained by a different team, or a truly independent open-source dependency) without wanting its full, independent history mixed into yours. Monorepos fit when several projects are developed TOGETHER, by the same team, and genuinely benefit from atomic cross-project commits and unified tooling.
- 05
Submodules have a real reputation for being genuinely fiddly in practice — the extra clone step, needing to explicitly
git submodule updateafter a submodule's pinned commit changes, and easily forgetting either — which is exactly why many teams facing a similar problem choose a monorepo (or a proper package manager / artifact registry, publishing a REAL versioned package instead of a submodule) rather than submodules specifically.
Code & diagrams
A submodule pins one external commit by reference; a monorepo just holds everything together directly.
Both the addition and the easy-to-forget clone/update steps.
cd ~/scratch/my-first-repo
# Add another repository as a submodule at a specific path
git submodule add https://github.com/example/shared-lib.git libs/shared-lib
git commit -m "Add shared-lib as a submodule"
# Your repo now records shared-lib's URL and its exact pinned commit
# Cloning a repo WITH submodules — the step people forget
git clone --recurse-submodules https://github.com/you/my-first-repo.git
# or, after a plain clone that skipped this:
git submodule update --init --recursive
# Updating a submodule to a newer commit is a deliberate, separate act
cd libs/shared-lib
git pull origin main
cd ../..
git add libs/shared-lib
git commit -m "Bump shared-lib to latest main"
# your repo now pins a NEW exact commit of the submoduleExplain it without notes
What exactly does a repository 'remember' about a submodule, versus what lives in the submodule's own separate repository?
You're deciding between splitting a frontend and backend into separate repos with a submodule link, or keeping them together in one monorepo. What's the key question that should drive this decision?
Practice
Add any small public repository as a submodule to a test repo, commit it, then delete the local clone entirely and re-clone with --recurse-submodules to see the difference versus a plain clone.
For a hypothetical frontend + backend project you're familiar with, decide whether a monorepo or separate repositories would genuinely fit better, and write one sentence explaining the reasoning.
Trade-offs
- ↔
Submodules give precise, explicit version pinning of an external dependency's exact source, but add genuine day-to-day friction (the extra clone step, manually updating pinned commits) that trips up even experienced developers regularly — a monorepo removes that friction for projects developed together, at the cost of a potentially very large repository and the need for more sophisticated build tooling to avoid rebuilding/retesting everything on every single change.
Done when you can
I understand what a submodule actually stores versus what lives in its own separate repository.
I know cloning a repo with submodules requires an extra step, and why.
I can reason about whether a monorepo or separate repositories genuinely fits a given situation.