skip to content

Hierarchical Project Paths

Colon-separated project paths, how they differ from project names, and how nested projects are referenced. Interviewers ask because path-versus-name confusion produces baffling 'project not found' errors.

on this pageshow

questions

5

What is a Gradle project path, and how does it differ from a project name?

level: juniorimportance: must knowfreq 55%

answer

  1. path = colon-separated, rooted at ':'
  2. name = last segment only
  3. name not globally unique, path is
  4. ':services:auth' vs name 'auth'
  5. logical path != physical dir

basics

~10 s

A project path is a colon-separated identifier like ':services:auth' that uniquely locates a project in the build tree. The name is just the last segment ('auth'); the path encodes its full position.

solid answer

~40 s

Every project in a multi-project Gradle build has a **path** and a **name**. The path is a colon-separated string rooted at the build root — `:` is the root project, `:services` is a child, `:services:auth` is a grandchild. It uniquely identifies the project across the whole build. The **name** is only the final path segment (`auth`) and need not be unique on its own — two projects under different parents can both be named `auth` because their paths differ. You use the path everywhere you reference another project: `include(':services:auth')` in `settings.gradle.kts`, `project(':services:auth')` in dependencies, and `:services:auth:build` to invoke a task. The path is logical, not necessarily filesystem-based — by default it mirrors the directory layout, but you can override the physical directory with `projectDir`.

code

kotlin · 7 lines
kotlin
// settings.gradle.kts
rootProject.name = "platform"
include(":services:auth")

// In any build.gradle.kts you can inspect them:
// project.path  -> ":services:auth"
// project.name  -> "auth"

go deeper

for a junior

Know that ':services:auth' is a path, 'auth' is the name (last segment), and the path uniquely identifies a project.

for a middle

Explain that names can repeat but paths cannot, and that paths are used for dependencies and task addressing.

for a senior

Discuss the logical-vs-physical decoupling (projectDir remapping) and how paths drive task/dependency resolution.

for a principal

Frame path conventions as part of a module naming/governance strategy in large monorepos, and the trade-offs of deep vs flat hierarchies.

## Path vs Name In a Gradle multi-project build, projects form a tree. Each node has two identifiers: - **Project path** — a colon-separated string describing the node's position in the tree, starting from the root. The root project's path is the single colon `:`. A direct child is `:services`; a child of that is `:services:auth`. The path is **globally unique** within the build. - **Project name** — the *last segment* of the path. For `:services:auth` the name is `auth`. Names are **not** required to be globally unique; `:services:auth` and `:platform:auth` can coexist because their full paths differ. ## Why two identifiers? Gradle needs an unambiguous handle to wire dependencies, resolve tasks, and address configuration. The path provides that. The name is a human-friendly short label and is what gets used (by default) for the published artifact's `archivesBaseName` and the project directory name. ## Where paths show up ```kotlin // settings.gradle.kts — declares the project into the tree include(":services:auth") // build.gradle.kts — a project dependency by path dependencies { implementation(project(":services:auth")) } ``` And on the command line, a task is addressed by the project path plus task name: `./gradlew :services:auth:test`. ## Path is logical, directory is physical By default the path `:services:auth` maps to the directory `services/auth` relative to the root. But the two are decoupled: in `settings.gradle.kts` you can remap `project(":services:auth").projectDir = file("modules/authentication")`. The path stays `:services:auth` regardless of where the files live. ## Accessing the root The leading colon means "from the root". `:auth` is a top-level project named `auth`; `auth` (no leading colon) in a task invocation is interpreted relative to the current project, which is rarely what you want in scripts — always qualify references with a leading colon for clarity.

  • Can two projects in the same build share a name?
    Yes, as long as their full paths differ — e.g. ':services:auth' and ':platform:auth' both have name 'auth' but distinct, unique paths.
  • What is the path of the root project?
    A single colon ':'. Its name is whatever rootProject.name is set to in settings.gradle.kts.

The path is like a file system absolute path (/services/auth) — unique and positional; the name is just the file name (auth), which can repeat in different folders.

saying these in an interview costs you the question

  • Saying the project name must be unique across the whole build (only the path must be).
  • Claiming the path always equals the directory path — it's logical and can be remapped with projectDir.

context

open as a page

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

level: middleimportance: must knowfreq 50%

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') { ... }.

open as a page

How does include(':services:auth') build out the project tree, and what does it imply about intermediate projects?

level: middleimportance: should knowfreq 40%

basics

~10 s

include(':services:auth') registers the leaf and implicitly creates any missing intermediate projects on the path (here ':services'). Each segment becomes a project node; intermediate ones exist even without their own build file.

open as a page

What does the leading colon mean in a Gradle project or task path, and why should you usually include it?

level: middleimportance: should knowfreq 45%

basics

~10 s

A leading colon means the path is absolute — resolved from the root project. Without it, the path is relative to the current project. Leading-colon (absolute) references are unambiguous, so scripts should use them.

open as a page

When does a project's hierarchical path stop matching its directory layout, and how do you handle it deliberately?

level: seniorimportance: should knowfreq 32%

basics

~20 s

The path is logical; the directory is physical. By default ':services:auth' maps to services/auth, but you can remap projectDir in settings.gradle.kts so the same path lives anywhere on disk, decoupling logical structure from physical layout.

open as a page