How to Balance Test Shards Evenly in CI
Splitting by file count leaves one slow shard as a straggler; splitting by duration keeps every shard finishing together.
Collect per-test durations, sort descending, and greedily place each test on the shard with the smallest running total (longest-processing-time-first).
Steps
- Record durations from a recent green run (JUnit or a runner timings file).
- Sort tests longest first.
- Assign each test to the currently lightest shard.
Terminal
Terminal
# LPT packing sketch: assign heaviest tests to the lightest shard
python - <<'PY'
tests = sorted(load_durations(), key=lambda t: -t.seconds)
shards = [[] for _ in range(3)]
totals = [0, 0, 0]
for t in tests:
i = totals.index(min(totals))
shards[i].append(t.name)
totals[i] += t.seconds
print(totals)
PYGotchas
- Balance is only as good as the timing data; refresh it as the suite grows.
- Fixed-size matrix shards cannot rebalance mid-run; use queue mode for that.
Related guides
How to Split Tests by Timing Data From JUnit ReportsBalance CI test shards using per-test durations from JUnit XML reports, packing tests into groups so each sha…
How to Split Tests Dynamically at Runtime in CIAssign tests to CI nodes at runtime with a shared work queue so a slow node simply takes fewer remaining test…