How to Handle Submodules with actions/checkout: A Complete Configuration Guide
Set the submodules input to true for top-level submodules or recursive for nested submodules in your actions/checkout step to automatically fetch, sync, and initialize Git submodules during your GitHub Actions workflow.
The actions/checkout repository provides the official GitHub Action for checking out repository contents in CI/CD workflows. When your project depends on Git submodules, you must explicitly configure how to handle submodules with actions/checkout to ensure all dependencies are available for your build process.
Understanding the Submodule Input Options
The submodules input parameter defined in action.yml controls whether and how submodules are fetched. According to the parsing logic in src/input-helper.ts, the action translates this input into internal flags that drive the checkout behavior.
true– Fetches only top-level submodules (direct children of the parent repository)recursive– Fetches all submodules, including nested submodules within other submodules- Unspecified or empty – Skips submodule fetching entirely
When you specify submodules: true, the action sets result.submodules to true. When you use submodules: recursive, the code additionally sets result.nestedSubmodules to true, which triggers recursive fetching of sub-submodules.
How actions/checkout Processes Submodules
According to the implementation in src/git-source-provider.ts, the action executes a specific sequence of Git commands to initialize submodules:
git submodule sync– Updates submodule URLs to match the parent repository's authentication settingsgit submodule update --init --force– Clones submodules and checks out the commits referenced by the parent repository--recursiveflag – Appended to the update command whennestedSubmodulesis enabled, ensuring all levels of nested submodules are fetched
The low-level Git operations are implemented in src/git-command-manager.ts, which provides the submoduleSync(), submoduleUpdate(), and submoduleForeach() methods. Additionally, src/git-auth-helper.ts propagates the same authentication tokens and SSH keys to each submodule, ensuring private submodules can be accessed using the credentials provided to the parent repository checkout.
Configuration Examples for Submodule Handling
Basic Top-Level Submodule Checkout
Use this configuration when your repository contains direct submodules without nested dependencies:
- uses: actions/checkout@v7
with:
submodules: true
token: ${{ secrets.GITHUB_TOKEN }}
Recursive Checkout for Nested Submodules
When your submodules contain their own submodules, use the recursive option to ensure all levels are fetched:
- uses: actions/checkout@v7
with:
submodules: recursive
token: ${{ secrets.GITHUB_TOKEN }}
Shallow Clone with Submodules
By default, the action performs shallow clones. To limit history in submodules:
- uses: actions/checkout@v7
with:
submodules: true
fetch-depth: 1
Full History for Submodules
When you need complete commit history for submodules (for example, for changelog generation or deep analysis), set fetch-depth: 0:
- uses: actions/checkout@v7
with:
submodules: recursive
fetch-depth: 0
Sparse Checkout with Submodules
When using sparse checkout, you must explicitly include submodule directory paths in your pattern:
- uses: actions/checkout@v7
with:
sparse-checkout: |
src/
lib/submodule/
submodules: true
Private Submodule Authentication
Private submodules inherit the same authentication as the parent repository. Configure SSH keys for submodule access:
- uses: actions/checkout@v7
with:
submodules: recursive
ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }}
ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
Summary
- Set
submodules: trueto fetch top-level submodules, orsubmodules: recursiveto include nested sub-submodules - The action processes submodules in
src/git-source-provider.tsusinggit submodule syncandgit submodule updatecommands - Authentication automatically propagates to submodules via
src/git-auth-helper.ts, using the same token or SSH key as the parent repository - Use
fetch-depth: 0when you need complete submodule history instead of shallow clones - Include submodule paths explicitly in
sparse-checkoutpatterns when using sparse checkout
Frequently Asked Questions
Does actions/checkout fetch submodules by default?
No. By default, actions/checkout ignores submodules completely. You must explicitly set the submodules input to either true or recursive to enable submodule fetching. When the input is empty or unspecified, the action in src/input-helper.ts leaves the submodule flags unset, and no submodule commands are executed.
How do I handle private submodules that require different credentials?
Private submodules automatically inherit the authentication credentials configured for the parent repository. The src/git-auth-helper.ts file handles credential propagation to submodules. You can provide access using either the token input for HTTPS authentication or ssh-key for SSH authentication. Ensure the provided credentials have repository access permissions for both the parent repository and all submodule repositories.
Can I use sparse checkout with submodules?
Yes, sparse checkout works with submodules, but you must explicitly include the submodule directory paths in your sparse-checkout pattern. If the submodule path is not included in the sparse checkout specification, the submodule will not be fetched even when submodules: true is set. The sparse checkout filtering applies before submodule initialization.
Why are my nested submodules not being checked out?
Nested submodules require the recursive value rather than true. When you set submodules: true, the action in src/git-source-provider.ts only processes top-level submodules. Change your configuration to submodules: recursive to ensure src/git-command-manager.ts appends the --recursive flag to the git submodule update commands, enabling the fetching of sub-submodules.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →