# How to Checkout Submodules with actions/checkout: Configuration Guide and Examples

> Easily checkout submodules with actions/checkout. Configure the GitHub Action to fetch top-level or nested submodules automatically in your workflow.

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

---

**Set the `submodules` input to `true` for top-level submodules or `recursive` for nested submodules when using the `actions/checkout` GitHub Action to automatically fetch Git submodules during your workflow.**

The `actions/checkout` repository provides a robust solution for cloning repositories in GitHub Actions workflows, including comprehensive support for Git submodules. When you need to checkout submodules with actions/checkout, the action handles the complex Git command orchestration internally while exposing a simple configuration interface. This implementation ensures that both public and private submodules are fetched using the appropriate authentication credentials.

## How the Submodules Input Is Parsed and Executed

According to the source code in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts), the action parses the `submodules` input to determine the checkout behavior. When you set `submodules: true`, the flag `result.submodules` becomes `true`; when you set `submodules: recursive`, the additional flag `result.nestedSubmodules` is also set to `true`.

During the checkout process, [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) orchestrates the submodule synchronization. The action executes `git submodule sync` to ensure submodule URLs match the parent repository's authentication settings. It then runs `git submodule update --init --force` to clone the submodules and checkout the correct commits.

If `nestedSubmodules` is enabled, the action passes the `--recursive` flag to fetch sub-submodules. 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` helper methods.

Additionally, [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts) updates the Git credential helper for each submodule. This ensures that the same `token` or `ssh-key` used for the main repository is available when fetching private submodules.

## Submodule Checkout Configuration Options

The `submodules` input accepts three distinct values that control submodule behavior:

- **`true`** – Checkout top-level submodules only, ignoring any nested sub-submodules.
- **`recursive`** – Checkout all submodules recursively, including nested sub-submodules.
- **(empty or omitted)** – Submodules are ignored; only the main repository is checked out.

## Practical Code Examples for Submodule Checkout

### Basic Submodule Checkout (Top-Level Only)

Use this configuration when your repository contains only top-level submodules and you do not need nested dependencies.

```yaml
- uses: actions/checkout@v7
  with:
    submodules: true          # fetch only top-level submodules

    token: ${{ secrets.GITHUB_TOKEN }}

```

### Recursive Checkout for Nested Submodules

When your project contains nested submodules, specify `recursive` to ensure all levels are fetched.

```yaml
- uses: actions/checkout@v7
  with:
    submodules: recursive    # fetch all submodules recursively

    token: ${{ secrets.GITHUB_TOKEN }}

```

### Shallow Fetch with Submodules

To minimize checkout time, combine submodules with a shallow fetch depth. Note that this retrieves only the latest commit for each submodule.

```yaml
- uses: actions/checkout@v7
  with:
    submodules: true
    fetch-depth: 1          # default – only the tip of each submodule

```

### Full History for Submodules

When you need complete commit history for submodules, set `fetch-depth: 0` to fetch all history for both the main repository and submodules.

```yaml
- uses: actions/checkout@v7
  with:
    submodules: recursive
    fetch-depth: 0          # fetch all history for the main repo and submodules

```

### Sparse Checkout Including Submodule Paths

Submodule fetching works with sparse-checkout, but you must explicitly include the submodule directory paths in your pattern.

```yaml
- uses: actions/checkout@v7
  with:
    sparse-checkout: |
      src/
      lib/submodule/    # ensure the submodule path is listed

    submodules: true

```

### Private Submodules with SSH Authentication

For private submodules, use an SSH key to ensure authentication propagates to submodule repositories.

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

```

## Authentication Behavior for Submodules

Submodules inherit the same authentication credentials as the main repository. The [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts) file handles credential propagation, ensuring that the `token` or `ssh-key` provided in the workflow step is used when fetching private submodules. You do not need to configure separate authentication for submodules unless they reside on different hosts requiring different credentials.

## Summary

- Set `submodules: true` to checkout top-level submodules, or `submodules: recursive` to include nested submodules.
- The action executes `git submodule sync` and `git submodule update --init --force` via [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts) and [`src/git-command-manager.ts`](https://github.com/actions/checkout/blob/main/src/git-command-manager.ts).
- Authentication automatically propagates to submodules through [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts).
- Combine `submodules` with `fetch-depth` to control history depth, or with `sparse-checkout` to limit the working tree.
- Use `ssh-key` instead of `token` when accessing private submodules via SSH.

## Frequently Asked Questions

### Why are my nested submodules not being checked out?

If nested submodules are missing, you likely set `submodules: true` instead of `submodules: recursive`. The `true` value only fetches top-level submodules. According to the implementation in [`src/input-helper.ts`](https://github.com/actions/checkout/blob/main/src/input-helper.ts), you must explicitly set the input to `recursive` to enable the `nestedSubmodules` flag, which adds the `--recursive` flag to Git commands in [`src/git-source-provider.ts`](https://github.com/actions/checkout/blob/main/src/git-source-provider.ts).

### How do I authenticate private submodules in actions/checkout?

Private submodules automatically use the same authentication method as the main repository. If you use a `token`, it propagates to submodules via the credential helper configured in [`src/git-auth-helper.ts`](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts). For SSH-based authentication, provide the `ssh-key` and optionally `ssh-known-hosts` inputs, and the action will use this key for all submodule URLs.

### Can I use sparse-checkout with submodules?

Yes, sparse-checkout is compatible with submodules, but you must include the submodule directory paths in your `sparse-checkout` pattern. The submodule contents are fetched regardless of sparse-checkout settings, but the working tree will only populate the paths you specify.

### Does fetching submodules work with shallow clones?

Yes, the `fetch-depth` setting applies to submodules when `submodules` is enabled. By default, the action performs a shallow fetch (`fetch-depth: 1`) for both the main repository and submodules. Set `fetch-depth: 0` to retrieve complete history for all repositories.