skip to content

How do you reference and configure a deeply nested subproject from another project, using its hierarchical path?

level: middleimportance: must knowfreq 50%

answer

  1. project(':services:auth') resolves by path
  2. implementation(project(':...')) = module dependency
  3. project(':...') { } configures it cross-project
  4. depth doesn't matter for lookup
  5. UnknownProjectException = missing include or typo

basics

~10 s

Use 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 s

Gradle 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
kotlin
// 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

for a junior

Know that project(':services:auth') references the nested module and is used inside dependencies { implementation(project(':...')) }.

for a middle

Explain both uses (dependency vs cross-project config), the UnknownProjectException cause, and that depth is irrelevant.

for a senior

Recommend convention plugins over per-path configuration and explain how project dependencies resolve via consumable configurations and task ordering.

for a principal

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.

context