# How to Implement Test Sharding for Parallel Execution in Catch2

> Learn how to implement test sharding in Catch2 for faster parallel test execution. Discover the `--shard-count` and `--shard-index` CLI flags for efficient test distribution.

- Repository: [Catch Org/Catch2](https://github.com/catchorg/Catch2)
- Tags: how-to-guide
- Published: 2026-07-30

---

**Catch2 implements test sharding through the `--shard-count` and `--shard-index` CLI flags (or Bazel environment variables), which partition the test suite deterministically across workers via the `createShard` algorithm in [`src/catch2/internal/catch_sharding.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_sharding.hpp).**

Test sharding enables parallel execution of large test suites by splitting tests across multiple workers, CPU cores, or CI nodes. In the **catchorg/Catch2** framework, this capability is built directly into the test runner and requires no external tools. By configuring **test sharding** parameters, you can distribute your test load evenly while maintaining deterministic assignment and standard reporting workflows.

## Command-Line Interface for Test Sharding

Catch2 exposes sharding control through two primary command-line options parsed during startup:

- `--shard-count=<n>` – Specifies the total number of shards to divide the test suite into.
- `--shard-index=<i>` – Specifies the zero-based index of the current shard to execute.

These values are parsed into the `Config` object defined in [`src/catch2/catch_config.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_config.hpp) and accessed at runtime via `Config::shardCount()` and `Config::shardIndex()`. If sharding options are omitted, `shardCount` defaults to `1`, causing the runner to execute the entire suite without partitioning.

```bash

# Execute shard 2 of 4 total shards

./tests/MyTests --shard-count=4 --shard-index=2

```

## Bazel Integration

When running under Bazel, Catch2 detects the `BAZEL_TEST=1` environment variable and reads sharding configuration from standard Bazel environment variables instead of CLI flags:

| Environment Variable | Equivalent CLI Flag | Purpose |
|---------------------|---------------------|---------|
| `TEST_TOTAL_SHARDS` | `--shard-count` | Total number of shards |
| `TEST_SHARD_INDEX` | `--shard-index` | Index of current shard |
| `TEST_SHARD_STATUS_FILE` | N/A | Path to status file created on successful completion |

The integration is verified by the test script in [`tests/TestScripts/testBazelSharding.py`](https://github.com/catchorg/Catch2/blob/main/tests/TestScripts/testBazelSharding.py), which demonstrates launching the binary with these variables and validating the creation of the status file.

```bash
export BAZEL_TEST=1
export TEST_TOTAL_SHARDS=4
export TEST_SHARD_INDEX=1
export TEST_SHARD_STATUS_FILE=/tmp/shard.status
./tests/MyTests

```

## The Sharding Algorithm

The core partitioning logic resides in [`src/catch2/internal/catch_sharding.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_sharding.hpp) within the `createShard` function. This algorithm ensures deterministic and even distribution using integer arithmetic:

1. **Validation** – Verifies that `shardCount` is greater than `shardIndex`.
2. **Base calculation** – Computes `totalTestCount / shardCount` as the base number of tests per shard.
3. **Remainder distribution** – The first `totalTestCount % shardCount` shards receive one additional test to handle uneven division.
4. **Slice extraction** – Calculates start and end indices for the requested shard, then constructs a new container containing only the tests for that slice.

Because the algorithm relies solely on deterministic arithmetic, test assignment remains stable across runs provided the underlying test order is consistent (e.g., using `--order decl`).

## Implementation Flow

Test sharding integrates into the execution pipeline in [`src/catch2/catch_session.cpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_session.cpp). The `Session` class orchestrates the following sequence:

1. **Configuration parsing** – Command-line options populate the `Config` object.
2. **Test collection** – All test cases matching the current `TestSpec` are gathered into a `TestGroup`.
3. **Shard creation** – The session calls `createShard` with the collected tests, `shardCount`, and `shardIndex`:
   ```cpp
   m_tests = createShard(
       m_tests,
       m_config->shardCount(),
       m_config->shardIndex());
   ```

4. **Execution** – The `TestGroup` runs the filtered (sharded) test set, with reporters processing results as usual.

## Practical Examples

### Manual Sharding via CLI

Run a binary across three separate terminal sessions to parallelize execution:

```bash

# Terminal 1

./build/Tests/MyTests --shard-count=3 --shard-index=0

# Terminal 2

./build/Tests/MyTests --shard-count=3 --shard-index=1

# Terminal 3

./build/Tests/MyTests --shard-count=3 --shard-index=2

```

### Parallel CI Job Using Bash

Distribute tests across a single machine's cores using background processes:

```bash
#!/usr/bin/env bash
TEST_BINARY=./build/Tests/MyTests
TOTAL_SHARDS=5

for i in $(seq 0 $((TOTAL_SHARDS-1))); do
  $TEST_BINARY --shard-count=$TOTAL_SHARDS --shard-index=$i &
done

wait  # Wait for all shards to finish

```

### Bazel Test Rule Configuration

Define sharding directly in your `BUILD` file:

```bzl
cc_test(
    name = "my_test",
    srcs = ["my_test.cpp"],
    shard_count = 4,  # Bazel automatically sets TEST_TOTAL_SHARDS

)

```

## Summary

- **Test sharding** in Catch2 is controlled via `--shard-count` and `--shard-index` flags or Bazel environment variables.
- The `createShard` function in [`src/catch2/internal/catch_sharding.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_sharding.hpp) implements deterministic partitioning based on integer division and remainder distribution.
- Configuration values are accessed through `Config::shardCount()` and `Config::shardIndex()` as defined in [`src/catch2/catch_config.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_config.hpp).
- The `Session` class applies sharding during test execution in [`src/catch2/catch_session.cpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_session.cpp) before running the filtered test set.
- Bazel integration requires setting `BAZEL_TEST=1` and using `TEST_TOTAL_SHARDS`, `TEST_SHARD_INDEX`, and `TEST_SHARD_STATUS_FILE`.

## Frequently Asked Questions

### How does Catch2 distribute tests across shards?

Catch2 uses the `createShard` algorithm in [`src/catch2/internal/catch_sharding.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_sharding.hpp) to divide tests evenly. Each shard receives `totalTestCount / shardCount` tests, with the first `totalTestCount % shardCount` shards receiving one additional test to account for remainders.

### What happens if I don't specify sharding options?

If `--shard-count` is not specified, it defaults to `1`. The `createShard` function returns the original test container unchanged, causing the runner to execute the entire suite without partitioning.

### How do I enable Bazel-compatible test sharding?

Set the `BAZEL_TEST=1` environment variable and provide `TEST_TOTAL_SHARDS`, `TEST_SHARD_INDEX`, and optionally `TEST_SHARD_STATUS_FILE`. Catch2 will automatically detect these variables and skip parsing the corresponding CLI flags.

### Is the test distribution deterministic across runs?

Yes, provided the underlying test order is deterministic (e.g., using `--order decl` or consistent sorting). The sharding algorithm uses only arithmetic operations on the total test count and shard index, ensuring the same tests always map to the same shard indices.