In a Gradle multi-project build, how do you make one subproject depend on another subproject so it can use its classes and outputs?
answer
- project(":lib") notation
- no publishing — consumes build outputs
- auto task ordering
- configuration controls classpath
- include(...) in settings file
basics
~10 sAdd a project dependency in the consumer's build file, e.g. implementation(project(":lib")). Gradle builds :lib first and puts its compiled output and dependencies on the consumer's classpath.
solid answer
~30 sInside a multi-project build (subprojects listed in `settings.gradle.kts` via `include(":lib", ":app")`), one subproject depends on another by declaring a **project dependency** rather than an external coordinate: ```kotlin // app/build.gradle.kts dependencies { implementation(project(":lib")) } ``` The `project(":lib")` notation resolves to the sibling project. Gradle automatically wires task ordering so `:lib` is assembled before `:app` compiles, and `:lib`'s main output (its JAR / classes) plus its declared dependencies are placed on `:app`'s classpath according to the configuration used (`implementation`, `api`, `testImplementation`, etc.). You don't publish `:lib` to a repository — Gradle consumes its outputs directly from the build.
code
kotlin · 7 lines// settings.gradle.kts
include(":lib", ":app")
// app/build.gradle.kts
dependencies {
implementation(project(":lib"))
}go deeper
Recall the project(":lib") syntax and that it puts the other module's code on your classpath without publishing.
Explain task-ordering is automatic and that the configuration (implementation/api) governs classpath and transitivity.
Mention variant selection (apiElements/runtimeElements) and how attribute matching picks the right outgoing configuration of the java component.
Frame project dependencies as the substrate for module decomposition; discuss when to keep modules in one build vs split into separate published artifacts / composite builds.
## What a project dependency is A Gradle build can contain many **subprojects** (modules). They are declared in the settings file: ```kotlin // settings.gradle.kts rootProject.name = "my-build" include(":lib", ":app") ``` When one subproject needs another's code, you declare a **project dependency** using the `project(path)` notation instead of an external coordinate like `com.example:lib:1.0`. ```kotlin // app/build.gradle.kts dependencies { implementation(project(":lib")) } ``` ## How it differs from an external dependency - An **external dependency** (`implementation("group:name:version")`) is resolved from a repository (Maven Central, etc.). - A **project dependency** is resolved from the **build itself** — Gradle uses `:lib`'s produced artifacts (by default the main JAR / classes directory) without publishing anything. ## What Gradle does for you 1. **Task ordering / dependency graph** — `:app`'s `compileJava`/`compileKotlin` automatically depends on `:lib` being built (its `jar` or `classes`), so you never have to wire `dependsOn` manually. 2. **Classpath assembly** — `:lib`'s output and its *exported* dependencies are added to `:app`'s classpath, governed by the configuration (`implementation` vs `api`). 3. **Variant selection** — Gradle picks the right output **variant** of `:lib` (e.g. the `apiElements` / `runtimeElements` configuration of the `java` component) using attribute matching, so the consumer gets the correct compile vs runtime artifacts. ## The configuration matters The configuration you put the project dependency in controls visibility and transitivity: - `implementation(project(":lib"))` — `:lib` is on `:app`'s compile and runtime classpath, but is **not** leaked to anyone who depends on `:app`. - `api(project(":lib"))` — requires the `java-library` plugin; `:lib` is also exposed to `:app`'s consumers. - `testImplementation(project(":lib"))` — only for `:app`'s tests. ## Path notation Paths are colon-separated and rooted at the build: `:lib`, `:platform:core`, etc. The leading `:` means "from the root". A typo in the path fails fast at configuration time with "project ... not found".
- Do you have to publish :lib to a Maven repository for :app to use it?No. A project dependency consumes :lib's outputs directly from the build; nothing is published. Gradle builds :lib first and uses its produced artifacts and exported dependencies on :app's classpath.
- Does :app automatically build :lib first?Yes. The project dependency creates an edge in the task graph, so :app's compile/jar tasks depend on :lib's relevant tasks; Gradle orders them correctly without any manual dependsOn.
It's like importing code from a folder in your own repo instead of pulling a published library off the internet — same import syntax for you, but Gradle compiles the dependency locally first.
saying these in an interview costs you the question
- Saying you must publish the subproject to a repository first.
- Manually wiring dependsOn between compile tasks instead of using a project dependency.
- Using a file path like project("../lib") instead of the colon path project(":lib").