How does Gradle disambiguate task addressing when the root build and an included build both have a project or task with the same name?
answer
- first segment = build name
- per-build isolated namespaces
- duplicate subproject names are fine
- duplicate BUILD names fail
- override with name = ...
basics
~20 sThe first path segment is the build name. :lib:app:run targets the included build lib; :app:run targets the root build's app subproject. The build-name prefix removes ambiguity, so equal subproject names in different builds don't clash.
solid answer
~40 sEach build in a composite has its own isolated project namespace, so identical project or task names across builds never collide — they live in different builds. Addressing resolves the leading segment as a **build name** first: `:lib:app:run` is the `run` task in subproject `app` of the *included* build `lib`, while `:app:run` (no included-build prefix) is `run` in subproject `app` of the **root** build. The risk is purely the **build name** itself: if two included builds default to the same directory name (e.g. two `utils` directories), Gradle reports a duplicate-build-name conflict at configuration time, and you must override one via `includeBuild(...) { name = "..." }`. So disambiguation is structural: pick unique build names, and every task is then uniquely addressable as `:<uniqueBuildName>:<project-path>:<task>`.
code
kotlin · 4 lines// settings.gradle.kts — resolve a default-name collision
includeBuild("../team-a/utils") { name = "a-utils" }
includeBuild("../team-b/utils") { name = "b-utils" }
// now both addressable: ./gradlew :a-utils:build :b-utils:buildgo deeper
Know that the leading segment is a build name and projects are isolated per build.
Explain that duplicate subproject names are harmless but duplicate build names conflict, and how to override the name.
Reason about how unique build names keep both CLI and programmatic addressing deterministic.
Define naming conventions across teams' included builds to avoid systemic collisions in large composites.
## Namespaces are per-build In a composite, every included build is a **separate, isolated build** with its own root project, subprojects, and task containers. There is no global flattening. So an included build named `lib` and the root build can *both* have a subproject `app` with a `run` task — these are two distinct tasks living in two distinct builds. ## How a task path is resolved Gradle parses a path like `:lib:app:run` left to right: 1. The leading `:` followed by a segment is checked against **included build names** first when running a composite. 2. If the first segment matches an included build name (`lib`), the remainder (`:app:run`) is resolved *inside that build*. 3. If it does not match an included build, it is resolved as a project path inside the **root** build (`:app:run` → root build's `app` subproject). This is why two builds can each own an `app:run` without conflict — the build-name prefix selects the namespace. ## The real collision: duplicate build names The genuine ambiguity is at the **build level**. If you include two builds whose default names collide: ```kotlin includeBuild("../team-a/utils") includeBuild("../team-b/utils") // both default to name "utils" ``` Gradle fails the configuration with a build-name conflict. Fix it by overriding: ```kotlin includeBuild("../team-a/utils") { name = "a-utils" } includeBuild("../team-b/utils") { name = "b-utils" } ``` Now `:a-utils:build` and `:b-utils:build` are unambiguous. ## Programmatic equivalent The same uniqueness rule governs `gradle.includedBuild("a-utils")` — the lookup is by build name, so names must be unique for the handle lookup to be deterministic. ## Summary rule Keep **build names unique**; then `:<buildName>:<projectPath>:<task>` is a globally unique address, and no amount of duplicate *subproject* or *task* names inside different builds causes a clash.
- Can two included builds have a subproject with the same name?Yes. They live in separate builds, so `:lib1:core:test` and `:lib2:core:test` are distinct and unambiguous as long as the build names differ.
- What forces you to set an explicit `name` on an included build?When two included builds would otherwise default to the same name (e.g. same directory name). Gradle reports a build-name conflict until you override one.
saying these in an interview costs you the question
- Claiming included builds share a global project namespace.
- Thinking duplicate task names across builds cause errors — only duplicate build names do.