How does Gradle build the project hierarchy from include() declarations, and how do nested project paths map to directories?
answer
- colon path = tree node
- :web:api creates :web too
- default dir mirrors path
- project(":x").projectDir override
- rootProject.name = build identity
basics
~10 sinclude(":web:api") creates intermediate projects (:web and :web:api), each a Project node under rootProject. By default a project path maps to a matching directory; you can override the location with project(":api").projectDir.
solid answer
~40 sDuring initialization, each `include(...)` path becomes a node in the project tree rooted at `rootProject`. A colon-separated path like `:web:api` is hierarchical: Gradle ensures both `:web` and `:web:api` exist, with `:web:api` as a child of `:web`. By **convention**, the project directory mirrors the path — `:web:api` maps to `<root>/web/api`. When your layout differs, override it in settings: ```kotlin include(":api") project(":api").projectDir = file("modules/api-service") ``` The `rootProject.name` is the build's identity (independent of folder name). Each created `Project` is a placeholder during initialization; its `build.gradle.kts` runs later in configuration. You can also rename or relocate the root via `rootProject.projectDir`/`rootProject.buildFileName`. The hierarchy you build here is what `project(":web:api")` references and what configuration walks when evaluating build scripts.
code
kotlin · 8 lines// settings.gradle.kts
rootProject.name = "app"
include(":web:api") // materializes :web and :web:api
include(":data")
// Relocate :data to a non-conventional folder:
project(":data").projectDir = file("libs/data-access")go deeper
Know include adds a project and that folders usually match the path.
Explain colon-path hierarchy, intermediate-project materialization, and overriding projectDir.
Discuss stable project paths vs. directory reorganization and rootProject identity.
Standardize module layout/path conventions across many teams to keep references stable as repos evolve.
## From include to a tree The project hierarchy is a tree of `Project` objects with a single `rootProject` at the top. Each `include` path adds a node: ```kotlin rootProject.name = "app" include("core") // :core include(":web:api") // creates :web AND :web:api ``` Paths use `:` as the separator. `:web:api` is read as "project `api`, child of project `web`, child of root." If `:web` wasn't explicitly included, Gradle still materializes it as an intermediate (possibly empty) project so the path is valid. ## Path-to-directory mapping By default, the project's directory equals its path translated to folders: - `:core` -> `<root>/core` - `:web:api` -> `<root>/web/api` The leaf segment is also the default project name. When the on-disk layout doesn't match the logical path, override in settings: ```kotlin include(":api") project(":api").projectDir = file("services/api") // optionally: project(":api").buildFileName = "api.gradle.kts" ``` ## rootProject `rootProject.name` defines the build identity and is independent of the root folder name (good for reproducibility — the folder can be checked out under any name). You can also relocate or rename root scripts via `rootProject.projectDir` / `rootProject.buildFileName`, though that's rare. ## What exists after initialization At the end of initialization you have a fully-formed tree of `Project` objects, but **no build script has run**. References like `project(":web:api")` resolve against this tree. Configuration then visits the projects and evaluates each `build.gradle.kts`. Understanding this mapping matters when modules live in non-standard folders or when a project path must be stable even though directories are reorganized.
- If you include(":web:api") but never include(":web"), does :web exist?Yes — Gradle materializes the intermediate :web project automatically so the path is valid, even if it has no build script of its own.
- How do you point a project at a directory that doesn't match its path?Set project(":path").projectDir = file("custom/dir") in settings.gradle.kts.
saying these in an interview costs you the question
- Assuming rootProject.name must equal the checkout folder name.
- Thinking a non-standard module folder works without setting projectDir.
- Believing the build script of an included project runs during initialization.