skip to content

What is a composite build in Gradle, and how do you wire one using includeBuild?

level: juniorimportance: must knowfreq 55%

answer

  1. includeBuild in settings.gradle.kts
  2. each included build has its own settings file
  3. vs include(':sub') = one build many projects
  4. auto-substitutes matching group:name
  5. develop library + consumer together

basics

~10 s

A composite build combines otherwise independent Gradle builds into one. You wire it by adding includeBuild('../other-build') to settings.gradle.kts; Gradle then treats the included build as part of the current build.

solid answer

~40 s

A composite build is a build that *includes* one or more other standalone Gradle builds — each with its own `settings.gradle(.kts)` and its own build directory. You declare it in the **root settings file** with `includeBuild("../other-build")`. Unlike a subproject (which is added with `include(":sub")` and shares the root's settings/lifecycle), an included build keeps its own settings, its own configuration, and runs as a nested build. The most common use is replacing a binary dependency on a published library with its source build, so you can develop a library and its consumer side-by-side without publishing to a repository. Gradle automatically substitutes the dependency's group:name coordinates for the included build's outputs where they match.

code

kotlin · 12 lines
kotlin
// consumer/settings.gradle.kts
rootProject.name = "consumer"

// pull in a separate, standalone build that lives next door
includeBuild("../my-library")

// app/build.gradle.kts
dependencies {
    // resolves to ../my-library source build, not a published artifact,
    // because the coordinates match the included build's group:name
    implementation("com.example:my-library:1.0")
}

go deeper

for a junior

Know includeBuild('../other') goes in settings.gradle.kts and combines separate builds.

for a middle

Explain the subproject-vs-composite distinction and the automatic coordinate substitution use case.

for a senior

Discuss when composite beats a single multi-project build (independent release cadence, cross-repo dev) and the --include-build CLI form.

for a principal

Weigh composite builds as an architecture for splitting a monorepo into independently-releasable builds while keeping local cross-build development frictionless.

## What 'composite build' means Gradle distinguishes two ways to compose code: - **Multi-project (subproject) build** — one *single* build with a root project and child projects declared via `include(":app", ":lib")` in `settings.gradle.kts`. There is exactly **one** settings file and **one** build lifecycle. Subprojects share configuration, the buildscript classpath, and the dependency-resolution graph. - **Composite build** — a build that *includes other complete builds*, each of which has **its own** `settings.gradle(.kts)` and could be built entirely on its own. You wire these with `includeBuild`. ## Wiring with includeBuild In the **consuming build's** `settings.gradle.kts`: ```kotlin includeBuild("../my-library") ``` The path is the directory of another standalone build (it contains its own settings file). After this, the included build participates in the outer build. Its outputs can transparently replace external dependencies that share the same `group:name` coordinates — so a `implementation("com.example:my-library:1.0")` in the consumer resolves to the *source* build instead of a published artifact. ## Why use it 1. **Develop a library and its consumer together** without publishing snapshots to a local Maven repo between each change. 2. **Combine unrelated builds** for a one-off aggregate run. 3. **Isolate plugin builds** (a `build-logic` build included so its plugins can be applied) — though that is more about plugin development. ## How it differs operationally - Each included build configures **independently**; there is no shared root project across them. - Tasks in the outer build can depend on the included build's outputs; the dependency substitution is automatic for matching coordinates. - You can `includeBuild` from the command line too: `gradle --include-build ../my-library run`. ## Key DSL - `include(":sub")` → adds a **subproject** to *this* build. - `includeBuild("../other")` → composes a **separate build** into *this* build. These are not interchangeable: `include` expects a project path, `includeBuild` expects a directory containing its own settings file.

  • How does an included build differ from a subproject declared with include(':lib')?
    A subproject is part of the *same* build and shares the root settings and lifecycle; an included build is a *separate* standalone build with its own settings file, composed in via includeBuild.
  • Can you include a build from the command line without editing settings?
    Yes — gradle --include-build ../my-library <task> composes it for that invocation only.

A subproject is a room inside one house (shared foundation); a composite build is plugging two complete houses into one shared driveway — each keeps its own foundation and plumbing.

saying these in an interview costs you the question

  • Saying includeBuild and include do the same thing — include adds a subproject path, includeBuild composes a separate build directory.
  • Claiming the included build shares the root's settings.gradle — it keeps its own.

context