skip to content

What is Gradle's configuration-on-demand feature, and what problem does it solve in large multi-project builds?

level: middleimportance: must knowfreq 38%

answer

  1. configures only relevant projects
  2. root + task owners + project deps
  3. org.gradle.configureondemand / --configure-on-demand
  4. breaks with cross-project config
  5. superseded by configuration cache

basics

~10 s

Configuration on demand tells Gradle to configure only the projects needed for the requested tasks, instead of configuring every project in the build. It speeds up the configuration phase in large multi-project builds.

solid answer

~40 s

Every Gradle build has a **configuration phase** that runs each project's build script to build the task graph, followed by an **execution phase**. By default Gradle configures *all* projects, even ones irrelevant to the requested task — costly in builds with hundreds of subprojects. **Configuration on demand** (`--configure-on-demand` flag, or `org.gradle.configureondemand=true` in `gradle.properties`) makes Gradle configure only the root project plus the projects required to run the requested tasks, walking project dependencies to pull in transitively-needed projects. For a build with 200 modules where you only need one app and its dependencies, this can dramatically cut configuration time. It's an older optimization that predates the configuration cache; for new builds the configuration cache generally supersedes it and is the recommended path.

code

properties · 5 lines
properties
# gradle.properties
org.gradle.configureondemand=true

# or per-invocation:
# gradle :app:assemble --configure-on-demand

go deeper

for a junior

Know it configures only the projects needed for the requested tasks instead of all of them, enabled via a flag or gradle.properties.

for a middle

Explain the configuration vs execution phases, exactly which projects get configured (root + task owners + project deps), and how to enable it.

for a senior

Discuss its limitations with cross-project configuration and why the configuration cache supersedes it for modern builds.

for a principal

Frame it within an org's build-performance strategy: when to lean on it vs investing in configuration-cache compatibility across a large monorepo.

## The two phases of a Gradle build Every Gradle invocation runs in distinct phases: 1. **Initialization** — `settings.gradle(.kts)` runs; Gradle decides which projects participate. 2. **Configuration** — every participating project's build script is *executed* to register and wire up tasks, building the full task graph (the DAG). This runs even for projects you didn't ask to build. 3. **Execution** — the requested tasks (and their dependencies) actually run. In a build with many subprojects, the configuration phase is pure overhead for projects you never touch. If `:app` depends only on `:core`, configuring the other 198 modules is wasted work on every invocation. ## What configuration on demand does With configuration on demand enabled, Gradle configures **only the projects relevant to the requested tasks**: - The **root** project (always configured). - The projects that **own** the requested tasks. - Projects reachable through **project dependencies** (e.g. an `implementation(project(":core"))` dependency pulls `:core` in). Gradle discovers the needed set by evaluating projects lazily as task references and project dependencies are resolved, rather than eagerly evaluating all of them up front. ## How to enable it Two ways: ```properties # gradle.properties (persistent, per-project or per-user) org.gradle.configureondemand=true ``` ```bash # one-off, per invocation gradle :app:assemble --configure-on-demand ``` ## Caveats and limitations - It's a **heuristic**: builds with **cross-project configuration** (e.g. `allprojects { }`, `subprojects { }`, or one project reaching into another via `project(":other").tasks…`) can behave incorrectly, because the project that *would* configure another may never be configured. Gradle warns these builds are not well-supported under configure-on-demand. - It only helps when you run **a subset** of the build. A full `build` that touches everything sees little benefit. - It is **incubating/legacy** relative to the **configuration cache**, which caches the *result* of the entire configuration phase and reuses it across invocations — a strictly more powerful optimization. Modern guidance is to invest in making the build configuration-cache-compatible rather than relying on configure-on-demand. ## Mental model Configure-on-demand reduces *how much* of the configuration phase runs this time; the configuration cache reduces *whether the configuration phase runs at all* (by reusing a cached task graph). They target the same cost from different angles.

  • Which projects get configured when you run `:app:assemble` with configure-on-demand on, and `:app` depends on `:core`?
    The root project, `:app` (it owns the task), and `:core` (pulled in as a project dependency). Other unrelated subprojects are skipped.
  • Why does a full `./gradlew build` see little benefit from configure-on-demand?
    Because `build` typically touches every subproject, so the set of 'relevant' projects is essentially all of them — there's nothing to skip.

Like a buffet versus à la carte: by default Gradle cooks every dish (configures every project) whether or not you order it; configure-on-demand only cooks the dishes you actually ordered plus their required side ingredients.

saying these in an interview costs you the question

  • Claiming it speeds up the execution phase — it only trims the configuration phase.
  • Saying it configures only the single requested project (it also pulls in project dependencies and the root).
  • Confusing it with the build cache (which caches task *outputs*, not configuration).

context