skip to content

Parallel Project Execution

Running independent projects concurrently with --parallel, what decoupling requires, and how task dependencies serialize the work anyway. Interviewers ask why enabling --parallel sometimes changes nothing at all.

on this pageshow

questions

5

How do you enable parallel project execution in Gradle, and what exactly does it parallelize?

level: juniorimportance: must knowfreq 70%

answer

  1. --parallel flag / org.gradle.parallel=true
  2. tasks across DIFFERENT projects run concurrently
  3. within a project still sequential
  4. off by default
  5. needs decoupled projects

basics

~10 s

Pass --parallel on the command line, or set org.gradle.parallel=true in gradle.properties. Gradle then runs tasks from different projects concurrently using the daemon's worker threads, instead of one project at a time.

solid answer

~40 s

Parallel execution runs **tasks belonging to different projects** at the same time. You turn it on per-invocation with `--parallel`, or persistently by putting `org.gradle.parallel=true` in `gradle.properties` (project root or `~/.gradle`). It is off by default. Under the hood the daemon maintains a pool of worker leases (size = `org.gradle.workers.max`, defaulting to CPU count) and schedules ready tasks across projects onto that pool. Tasks *within a single project* still run sequentially in declared/dependency order — the win comes from independent modules building at once. The main prerequisite is that projects are **decoupled**: no project may reach into another project's model at execution time. The execution phase is parallelized; configuration is not (that needs configuration-on-demand or the configuration cache).

code

bash · 5 lines
bash
# one-off
./gradlew build --parallel

# persistent: gradle.properties
org.gradle.parallel=true

go deeper

for a junior

Know the flag and the property, and that it runs different modules at the same time.

for a middle

Explain the worker-lease pool, workers.max default, and that within-project tasks stay sequential.

for a senior

Tie it to the decoupled-projects requirement and how the task graph still enforces ordering across modules.

for a principal

Discuss rolling it out org-wide via init scripts / shared gradle.properties and the trade-offs vs configuration cache and remote build cache.

## What parallel execution does A Gradle build is a tree of *projects* (modules). By default Gradle executes the tasks of one project, then the next, in a single sweep. **Parallel project execution** lets Gradle run tasks from *different* projects simultaneously, which shortens wall-clock time on multi-module builds. It is **disabled by default**. Enable it two ways: - Command line: `./gradlew build --parallel` - Persistent: add `org.gradle.parallel=true` to `gradle.properties` (in the project root, or in `~/.gradle/gradle.properties` to apply to all builds). ## What is and isn't parallelized - **Across projects:** `:moduleA:compileJava` and `:moduleB:compileJava` can run at the same time if neither depends on the other. - **Within a project:** tasks still run sequentially, ordered by their dependency graph. - **Configuration phase:** *not* parallelized by this flag — every project is still configured (unless you also enable configuration-on-demand or the configuration cache). ## The worker-lease model The daemon holds a fixed number of *worker leases*, controlled by `org.gradle.workers.max` (default = number of CPU cores). Each running task occupies one lease. Gradle's scheduler walks the merged task graph, finds tasks whose dependencies are satisfied, and dispatches as many as there are free leases. This same lease pool is shared with the Worker API, so CPU-bound work doesn't oversubscribe the machine. ## The hard requirement: decoupled projects Tasks can only run concurrently if the projects are **decoupled** — a project must never directly access the mutable state (tasks, configurations, extensions, properties) of another project during configuration or execution. Cross-project wiring must go through proper dependencies (`project(":other")`) or lazy providers, not `project(":other").tasks.getByName(...).someValue` at execution time. Violating this can produce nondeterministic results or warnings. ```kotlin // gradle.properties // org.gradle.parallel=true // org.gradle.workers.max=8 ``` The net effect: independent modules compile, test, and jar concurrently, while dependency edges still force the correct ordering.

  • Does --parallel parallelize tasks within a single project?
    No. Tasks inside one project still run sequentially according to their dependency order; only tasks from different (decoupled) projects run concurrently.
  • What controls how many tasks run at once?
    org.gradle.workers.max (default = CPU core count). It sizes the daemon's worker-lease pool, which is shared with the Worker API.

saying these in an interview costs you the question

  • Claiming it's on by default — it is off by default.
  • Saying it parallelizes the configuration phase — it does not.
  • Confusing it with the Worker API (intra-task parallelism).

context

open as a page

What does it mean for projects to be 'decoupled', and why is decoupling a prerequisite for safe parallel (and configuration-on-demand) execution?

level: middleimportance: must knowfreq 55%

basics

~20 s

Decoupled projects don't directly touch each other's mutable state at configuration or execution time. They interact only through declared dependencies. Coupling (e.g. project(":other").tasks.getByName(...)) breaks parallel/on-demand assumptions because another project may not be configured or done yet.

open as a page

With --parallel enabled, how do task and project dependencies still serialize work, and how does Gradle decide what may run at the same time?

level: middleimportance: should knowfreq 45%

basics

~20 s

Gradle builds one merged task graph (a DAG). A task only runs once all its dependencies finish, so dependency edges force ordering even in parallel mode. Independent branches with no edges between them run concurrently up to the worker-lease limit.

open as a page

A multi-module build passes when run serially but intermittently fails or produces inconsistent outputs under --parallel. How do you diagnose and fix it?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Intermittent parallel-only failures usually mean coupled projects or undeclared task inputs/outputs causing races. Find the cross-project access or shared output, then fix it by declaring proper dependencies, declaring inputs/outputs accurately, or avoiding shared output paths.

open as a page

How does org.gradle.workers.max interact with --parallel, and how would you reason about setting it on a CI agent versus a developer laptop?

level: seniorimportance: should knowfreq 35%

basics

~20 s

org.gradle.workers.max caps the number of concurrent worker leases the daemon hands out, defaulting to CPU core count. --parallel uses that pool to run cross-project tasks. On constrained or container CI agents you often lower it; for wide builds on big machines you may raise it.

open as a page