Git Submodules
A Git submodule is a repository nested inside another repository. It allows a project to include and track an external Git repository at a specific commit, while keeping the two repositories fully independent.
Real-life analogy: Think of a submodule like including a published library in a project. The library lives in its own repository, maintained by others. Rather than copying the library's code directly into the project, a reference is kept — "use this specific version of this external library." If the library is updated, there is control over when (and whether) to update the reference.
When to Use Submodules
- A shared library or component is used across multiple projects
- An external project needs to be tracked at a specific version
- A project has a dependency that is maintained in a separate repository
- Splitting a monorepo into multiple smaller repos while still being able to work on them together
Adding a Submodule
git submodule add <repository-url> <path>Example
# Add a shared UI library as a submodule in the "libs/ui-components" folder
git submodule add https://github.com/company/ui-components.git libs/ui-components
This creates two things:
- A new folder
libs/ui-components/with the submodule's contents - A
.gitmodulesfile in the root that records the submodule configuration
The .gitmodules file looks like:
[submodule "libs/ui-components"]
path = libs/ui-components
url = https://github.com/company/ui-components.git
Commit both the .gitmodules file and the submodule entry:
git add .gitmodules libs/ui-components
git commit -m "Add ui-components as a submodule"
Cloning a Repository with Submodules
When someone clones a repository that has submodules, the submodule folders will be empty by default. The submodule contents must be fetched separately.
Option 1 — Recursive Clone (All in One Step)
git clone --recurse-submodules https://github.com/company/main-project.gitOption 2 — Initialize After Cloning
git clone https://github.com/company/main-project.git
cd main-project
git submodule init
git submodule update
One-Line Version of Option 2
git submodule update --initTo also initialize nested submodules (submodules within submodules):
git submodule update --init --recursiveViewing Submodule Status
git submodule statusOutput:
a3f92b1 libs/ui-components (v2.1.0)
The hash shown is the specific commit of the submodule that the parent project is currently using.
Updating a Submodule to the Latest Commit
# Update one submodule
git submodule update --remote libs/ui-components
# Update all submodules
git submodule update --remote
After updating, the parent repository sees the submodule's pointer has changed. Stage and commit this change:
git add libs/ui-components
git commit -m "Update ui-components submodule to latest"
Working Inside a Submodule
# Navigate into the submodule directory
cd libs/ui-components
# It is a fully independent Git repo
git log --oneline
# Switch to a branch
git switch main
# Make changes and commit
git add .
git commit -m "Fix button alignment"
git push origin main
# Go back to parent project
cd ../..
# Stage the updated submodule pointer
git add libs/ui-components
git commit -m "Update ui-components to latest"
Removing a Submodule
Removing a submodule involves several steps:
# Step 1: Remove the submodule entry from .gitmodules
git submodule deinit -f libs/ui-components
# Step 2: Remove from .git/modules
rm -rf .git/modules/libs/ui-components
# Step 3: Remove the actual directory
git rm -f libs/ui-components
# Step 4: Commit the removal
git commit -m "Remove ui-components submodule"
Limitations of Submodules
- They add complexity — new developers often forget to initialize them
- Keeping multiple submodule versions in sync across a team requires discipline
- Not intuitive for beginners — common source of confusion
Modern alternatives to submodules include Git subtrees and package managers (npm, pip, Maven, etc.) for managing dependencies.
Summary
Git submodules allow embedding one Git repository inside another. They are useful for shared libraries and components across multiple projects. The key commands are git submodule add to add, git submodule update --init to initialize after cloning, and git submodule update --remote to pull the latest version. Always commit the updated submodule pointer in the parent repository after making submodule changes.
