Lesson 20 of 30
Submodules let one repo embed another at an exact commit. In practice, most teams find the coordination overhead isn't worth it — and reach for a monorepo instead.
15 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A submodule is a Git repository nested inside another Git repository, pinned to one specific commit. The parent repo doesn't store the submodule's files — it stores a pointer: "at this path, check out this exact commit of that other repo." This is how you share code across repos (a design-system package, a shared library) while keeping each one's own history and versioning independent.
A monorepo is the opposite approach to the same underlying problem — instead of splitting related code into separate repos and stitching them back together, you keep everything in one repo, one history, one set of commits touching multiple projects at once.
git submodule add https://github.com/acme/design-tokens.git packages/design-tokens
This clones design-tokens into packages/design-tokens/ and creates a .gitmodules file at the repo root:
[submodule "packages/design-tokens"]
path = packages/design-tokens
url = https://github.com/acme/design-tokens.git
Committing this doesn't commit the submodule's files — it commits a special "gitlink" entry that records the exact commit SHA the submodule is pinned to. git status on the parent repo shows the submodule as a single pending change, not a folder full of files.
Anyone freshly cloning the parent repo gets an empty packages/design-tokens/ folder unless they also initialize submodules:
git clone --recurse-submodules https://github.com/acme/main-app.git
# or, after a plain clone:
git submodule update --init --recursive
To pull in the submodule's latest upstream changes and bump the pin:
cd packages/design-tokens
git pull origin main
cd ../..
git add packages/design-tokens
git commit -m "chore: bump design-tokens to latest"
That last git add is committing the new pinned commit, not any file content — the parent repo now points at a different SHA of the child repo.
git add and commit the pointer change in the parent. Someone else pulling the parent gets the old submodule content until that second commit lands.git clone of a repo with submodules leaves those folders empty. It's a constant source of "why is this directory blank" confusion for anyone who doesn't know to pass --recurse-submodules or run git submodule update --init.Blobs, trees, and commits are the objects you meet everywhere else in Git. A submodule reference is the fourth kind — a "gitlink" — a tree entry that points at a commit in a different repository entirely, rather than at a blob or another tree. It's the same commit-addressing idea from tagging and detached HEAD (a fixed pointer to one exact snapshot), just crossing a repository boundary instead of staying inside one.