skip to content

A colleague set org.gradle.workers.max=8 expecting the build to run modules in parallel, but it still runs them one at a time. Why, and what did they confuse it with?

level: middleimportance: should knowfreq 35%

answer

  1. workers.max = ceiling, not enabler
  2. parallel=true enables cross-project overlap
  3. ceiling alone -> idle leases
  4. forks/Worker API don't need parallel flag
  5. module overlap needs parallel=true

basics

~10 s

max-workers only sets a ceiling; it doesn't enable cross-project parallel execution. For that you need org.gradle.parallel=true. They confused the budget cap with the parallel-execution switch.

solid answer

~40 s

`org.gradle.workers.max` is purely a *ceiling* on concurrent work — it permits up to N concurrent units but does not, by itself, decide that independent projects may overlap. Parallel execution *across projects* is gated by a separate switch, `org.gradle.parallel=true`. With parallel off, Gradle executes one project's tasks at a time, so an 8-lease budget simply goes unused for cross-module overlap. The colleague conflated the budget (`workers.max`) with the enabler (`parallel`). The correct fix is to set `org.gradle.parallel=true` (so cross-project work is *eligible* to overlap) and keep `workers.max` sized as the ceiling for how much overlap actually happens. Note: some concurrency (test forks, Worker API items within a project) doesn't need the parallel flag — but module-level overlap does.

code

properties · 3 lines
properties
# gradle.properties
org.gradle.parallel=true   # enable cross-project overlap (the switch)
org.gradle.workers.max=8   # cap how much overlap happens (the ceiling)

go deeper

for a junior

Know that there's a separate org.gradle.parallel flag and max-workers is just a cap.

for a middle

Clearly separate 'enabler' (parallel) from 'ceiling' (workers.max) and note forks/Worker API don't need the flag.

for a senior

Add that the dependency graph and project independence ultimately determine achievable parallelism.

for a principal

Set sensible org defaults (parallel on, workers.max pinned) and educate teams on structuring modules for independence.

## Two distinct concepts 1. **`org.gradle.parallel=true`** — *enables* parallel project execution: tasks belonging to **different, independent projects** become eligible to run at the same time. This is the on/off switch for cross-module overlap. 2. **`org.gradle.workers.max`** — *bounds* how many work items run concurrently overall. It's the ceiling, shared by everything. A ceiling alone produces no parallelism. If nothing is *eligible* to overlap (parallel execution disabled, or the graph is a single linear dependency chain), the leases sit idle no matter how high `workers.max` is. ## What each one is responsible for ```properties # gradle.properties org.gradle.parallel=true # MAY overlap independent projects org.gradle.workers.max=8 # but never more than 8 things at once ``` Think of it as: `parallel` decides *whether* overlap is allowed; `workers.max` decides *how much*. You typically want both. ## Important nuance Not all concurrency needs the `parallel` flag: - **Test forks** (`maxParallelForks`) and **Worker API** work items run concurrently *within a single project* and consume leases even with `parallel=false`. - But **task overlap between separate subprojects** requires `org.gradle.parallel=true`. So a single-module build sees no benefit from `parallel`, while a multi-module build needs it for the modules to overlap. ## The diagnosis Symptom: modules run serially despite a high worker budget. Cause: `parallel` not enabled. Fix: enable it, verify modules are actually independent (a deep dependency chain still serializes), and keep `workers.max` as the ceiling. This is the canonical 'budget vs enabler' confusion.

  • Even with parallel=true and workers.max=8, two modules still run serially. Give a reason.
    They're not independent — one module's tasks depend on the other's outputs, so the dependency graph forces ordering. Parallelism only applies to projects with no inter-dependency at that point.
  • Does a single-module project benefit from org.gradle.parallel=true?
    Not for cross-project overlap (there's only one project). It can still benefit from within-project concurrency like test forks and Worker API items, which don't require the flag.

saying these in an interview costs you the question

  • Asserting workers.max alone turns on parallel module execution.
  • Forgetting that module dependencies can still serialize even when parallel is enabled.
  • Thinking the parallel flag is needed for test forks to run concurrently.

context