# How to Handle Submodules with actions/checkout: A Complete Configuration Guide

> Easily manage Git submodules in GitHub Actions. Configure actions/checkout with the submodules input to fetch, sync, and initialize submodules automatically.

- Repository: [GitHub Actions/checkout](https://github.com/actions/checkout)
- Tags: how-to-guide
- Published: 2026-07-05

---

**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`](https://github.com/actions/checkout/blob/main/action.yml) controls whether and how submodules are fetched. According to the parsing logic in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/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`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts), the action executes a specific sequence of Git commands to initialize submodules:

1. **`git submodule sync`** – Updates submodule URLs to match the parent repository's authentication settings
2. **`git submodule update --init --force`** – Clones submodules and checks out the commits referenced by the parent repository
3. **`--recursive` flag** – Appended to the update command when `nestedSubmodules` is enabled, ensuring all levels of nested submodules are fetched

The low-level Git operations are implemented in [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts), which provides the `submoduleSync()`, `submoduleUpdate()`, and `submoduleForeach()` methods. Additionally, [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/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:

```yaml
- 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:

```yaml
- 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:

```yaml
- 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`:

```yaml
- 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:

```yaml
- 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:

```yaml
- uses: actions/checkout@v7
  with:
    submodules: recursive
    ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }}
    ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}

```

## Summary

- Set `submodules: true` to fetch top-level submodules, or `submodules: recursive` to include nested sub-submodules
- The action processes submodules in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) using `git submodule sync` and `git submodule update` commands
- Authentication automatically propagates to submodules via [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts), using the same token or SSH key as the parent repository
- Use `fetch-depth: 0` when you need complete submodule history instead of shallow clones
- Include submodule paths explicitly in `sparse-checkout` patterns 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`](https://github.com/actions/checkout/blob/main/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`](https://github.com/actions/checkout/blob/main/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`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) only processes top-level submodules. Change your configuration to `submodules: recursive` to ensure [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts) appends the `--recursive` flag to the `git submodule update` commands, enabling the fetching of sub-submodules.