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?
answer
- workers.max = ceiling, not enabler
- parallel=true enables cross-project overlap
- ceiling alone -> idle leases
- forks/Worker API don't need parallel flag
- module overlap needs parallel=true
basics
~10 smax-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# 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
Know that there's a separate org.gradle.parallel flag and max-workers is just a cap.
Clearly separate 'enabler' (parallel) from 'ceiling' (workers.max) and note forks/Worker API don't need the flag.
Add that the dependency graph and project independence ultimately determine achievable parallelism.
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.