How do you reference and configure a deeply nested subproject from another project, using its hierarchical path?
answer
- project(':services:auth') resolves by path
- implementation(project(':...')) = module dependency
- project(':...') { } configures it cross-project
- depth doesn't matter for lookup
- UnknownProjectException = missing include or typo
basics
~10 sUse the full colon-separated path with project(':services:auth'). It returns the Project for that nested module, which you can use in dependencies(project(':services:auth')) or to configure it, e.g. project(':services:auth') { ... }.
solid answer
~50 sGradle exposes a nested project via its hierarchical path. `project(":services:auth")` looks up the project whose path is exactly `:services:auth` and returns its `Project` object. The most common use is in a dependency block: `implementation(project(":services:auth"))` creates a project dependency so the consumer compiles against the producer's outputs and Gradle wires task ordering. You can also configure a nested project from elsewhere (typically the root build script) with `project(":services:auth") { ... }`, which applies the closure/lambda to that project. Because the lookup is by path, the depth doesn't matter — `:a:b:c:d` works the same as `:a`. If the path doesn't correspond to an included project, Gradle throws `UnknownProjectException`, which usually means you forgot the matching `include(...)` in `settings.gradle.kts`, or mistyped a segment. Note configuration ordering: configuring a sibling project this way relies on cross-project configuration rules, so prefer `allprojects`/`subprojects` or convention plugins for broad config.
code
kotlin · 12 lines// services/gateway/build.gradle.kts
plugins { id("java-library") }
dependencies {
// depend on the deeply-nested auth module by its full path
implementation(project(":services:auth"))
}
// root build.gradle.kts — configure a nested project by path
project(":services:auth") {
group = "com.acme.platform"
}go deeper
Know that project(':services:auth') references the nested module and is used inside dependencies { implementation(project(':...')) }.
Explain both uses (dependency vs cross-project config), the UnknownProjectException cause, and that depth is irrelevant.
Recommend convention plugins over per-path configuration and explain how project dependencies resolve via consumable configurations and task ordering.
Set org-wide conventions: paths as the module contract, plugins for shared config, and guardrails against fragile cross-project path configuration.
## Looking up a nested project The `project(path)` method on `Project` resolves a project **by its absolute path** and returns the corresponding `Project` instance: ```kotlin val auth = project(":services:auth") // org.gradle.api.Project ``` Depth is irrelevant to the lookup — a three- or four-level path resolves the same way as a top-level one, because Gradle indexes projects by path. ## Two uses **1. Project (module) dependencies.** This is the dominant use: ```kotlin dependencies { implementation(project(":services:auth")) } ``` This declares that the current project depends on the *outputs* of `:services:auth`. Gradle resolves the dependency through `auth`'s `consumable` outgoing configurations, and automatically orders `auth`'s `jar` before this project's `compileJava`. **2. Cross-project configuration.** You can apply configuration to a nested project from another script (usually the root): ```kotlin project(":services:auth") { apply(plugin = "java-library") dependencies { // ... } } ``` This is equivalent to writing that config inside `services/auth/build.gradle.kts`. For broad, repeated config across many projects, prefer `subprojects { }`, `allprojects { }`, or — best practice — a **convention plugin** in `buildSrc`/an included build, rather than path-by-path configuration. ## Errors and gotchas - `UnknownProjectException: Project with path ':services:auth' could not be found` → the project was never `include`d in `settings.gradle.kts`, or a path segment is misspelled. The path in `include` and the path in `project(...)` must match exactly. - Configuring another project by path couples scripts and can create ordering surprises; convention plugins are the maintainable alternative. ## Inspecting paths programmatically `project.path`, `project.name`, and `project.parent?.path` let you reason about the tree at configuration time. `rootProject` always gives the root regardless of where you are.
- What exception do you get if you reference project(':services:auth') but never included it?UnknownProjectException — Gradle reports the path could not be found. Add the matching include(':services:auth') in settings.gradle.kts (or fix the typo).
- Is configuring a nested project via project(':...') { } the recommended way to share config?No. For repeated config across modules prefer convention plugins (buildSrc / included build) or subprojects/allprojects; per-path configuration couples scripts and is harder to maintain.
- Does the nesting depth affect how project(':a:b:c') resolves?No — Gradle resolves projects by exact path from an index, so any depth resolves identically as long as that path was included.
saying these in an interview costs you the question
- Using a relative path like project('auth') from a sibling and expecting it to find a deeply nested project.
- Claiming project(':services:auth') will create the project — it only resolves an already-included one.