Submodules & Monorepos

Sometimes one repo needs to contain another. By the end of this lesson you'll add a submodule, understand why fresh clones leave it empty, update it safely, and know when a monorepo is the simpler choice instead.

Learn Submodules & Monorepos in our free Git course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Git course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

1️⃣ Adding a Submodule

git submodule add <url> <path> clones another repo into your project and registers it. Git creates a .gitmodules file (the path + URL, which you commit and share) and a special gitlink at the path that pins one exact commit.

2️⃣ What Gets Committed

The parent stores a pointer to one specific commit of the submodule — not a copy of its files. That's the whole point: every teammate checks out the same version. Notice the 160000 mode in the commit output — that's Git's marker for a gitlink.

3️⃣ The Empty-Folder Surprise

The most common submodule confusion: a plain git clone leaves submodule folders empty , because their contents aren't fetched by default. Fix it with git submodule update --init --recursive , or avoid it entirely by cloning with --recurse-submodules .

Your turn. Add a submodule and make a fresh clone fill it in. Fill in the two blanks.

4️⃣ Updating a Submodule

To move a submodule forward, update it inside its folder, then commit the changed pointer in the parent . Forgetting that second commit (or to push the submodule's own new commits) is the classic way teammates end up on the wrong version.

5️⃣ Submodules vs. Monorepos

A monorepo keeps multiple projects in one repository, so tightly-coupled code is versioned and changed together in a single atomic commit — ideal when cross-cutting changes are common. Submodules keep each project independent, linked by commit pointers — better when components have separate owners, lifecycles, or release schedules. Because submodules add ceremony and footguns, many teams reach for a monorepo (or a package manager) unless they truly need separate repositories.

📋 Quick Reference

No commands given this time — just the plan. Embed a library as a submodule, prove the empty-folder fix, and weigh up a monorepo.

Practice quiz

What is a Git submodule?

  • A branch inside a folder
  • A type of merge
  • A separate Git repository embedded at a fixed commit inside a parent repo
  • A compressed archive

Answer: A separate Git repository embedded at a fixed commit inside a parent repo. A submodule is another repo nested in yours, pinned to a specific commit rather than copied.

Which command adds a submodule?

  • git submodule add <url> <path>
  • git add submodule <url>
  • git clone --sub <url>
  • git module add <url>

Answer: git submodule add <url> <path>. git submodule add <url> <path> registers and clones the submodule into the given path.

What file records a repo's submodules?

  • .gitignore
  • .submodules
  • .git/config only
  • .gitmodules

Answer: .gitmodules. The .gitmodules file (committed to the repo) lists each submodule's path and URL.

What exactly does the parent repo store for a submodule?

  • A full copy of the files
  • A pointer to one specific commit of the submodule
  • Just the URL
  • Nothing

Answer: A pointer to one specific commit of the submodule. The parent pins the submodule to an exact commit (a 'gitlink'), so everyone gets the same version.

After cloning a repo with submodules, why are the submodule folders empty?

  • Submodule contents aren't fetched by default — you must init/update them
  • A bug
  • They were deleted
  • They need a rebuild

Answer: Submodule contents aren't fetched by default — you must init/update them. A plain clone leaves submodules uninitialized; their files arrive only after init/update.

Which command initializes and fetches submodule contents after a clone?

  • git submodule fetch
  • git pull --sub
  • git submodule init && git submodule update
  • git checkout --sub

Answer: git submodule init && git submodule update. git submodule update --init (optionally --recursive) fills in the submodule files.

How do you clone a repo AND its submodules in one step?

  • git clone --all
  • git clone --recurse-submodules <url>
  • git clone --deep
  • git clone --modules

Answer: git clone --recurse-submodules <url>. git clone --recurse-submodules clones the parent and populates submodules together.

To move a submodule to its latest upstream commit, you...

  • delete and re-add it
  • run git merge
  • edit .gitmodules
  • cd into it, pull, then commit the new pointer in the parent

Answer: cd into it, pull, then commit the new pointer in the parent. You update the submodule, then commit the changed pointer in the parent so the new commit is recorded.

When is a monorepo often preferred over submodules?

  • Never
  • When tightly-coupled code should be versioned and changed together atomically
  • Only for tiny repos
  • Only for binaries

Answer: When tightly-coupled code should be versioned and changed together atomically. A monorepo keeps interdependent projects in one repo so cross-cutting changes land in a single commit.

A common pain point of submodules is...

  • They run too fast
  • They can't be cloned
  • It's easy to forget to commit/push the updated submodule pointer
  • They delete the parent

Answer: It's easy to forget to commit/push the updated submodule pointer. Forgetting to commit the moved pointer (or to push the submodule) leaves teammates on the wrong commit.