Multi-Project Builds
Structuring a build across many projects: include(), project dependencies, sharing logic with convention plugins, and composite builds. Interviewers ask because the old subprojects {} habit is exactly what modern Gradle wants you to unlearn.
on this pageshowhide
explore
- Project Structure & Layout30 questions
- Declaring Subprojects with include5 questions
- Hierarchical Project Paths5 questions
- Custom projectDir & buildFileName5 questions
- Flat Layouts with includeFlat5 questions
- Cross-Project Configuration Ordering5 questions
- Cross-Project Dependencies20 questions
- Project Dependencies project(':lib')5 questions
- The Project Dependency Graph & Task Ordering5 questions
- Sharing Test Fixtures Across Projects5 questions
- Shared Configuration30 questions
- Composite Builds20 questions
- Wiring Builds with includeBuild5 questions
- Dependency Substitution Across Builds5 questions
- Addressing Tasks in Included Builds5 questions
questions
100 · 4 sectionsWhat is a Gradle project path, and how does it differ from a project name?
basics
~10 sA 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.
How do you register subprojects in a Gradle multi-project build, and which file does that belong in?
basics
~10 sIn settings.gradle.kts you call include(":app", ":lib"). Each path becomes a project in the build. Subprojects are NOT declared in build.gradle.kts — only the settings file defines which projects exist.
What does customizing a subproject's projectDir in settings.gradle.kts let you do, and how do you set it?
basics
~10 sIt decouples a project's logical path (like ':lib') from its folder on disk. In settings.gradle.kts you write project(":lib").projectDir = file("libs/lib") so ':lib' lives in a different directory than the default ./lib.
In a Gradle multi-project build, what is the difference in responsibility between settings.gradle.kts and build.gradle.kts?
basics
~10 ssettings.gradle.kts defines the build's structure — which projects exist (via include). build.gradle.kts defines what a single project does — its plugins, dependencies, and tasks.
In a Gradle multi-project build, what determines the order in which projects are configured (evaluated), and is that order guaranteed?
basics
~10 sGradle configures projects in an order it chooses; by default the root is evaluated first, but the order among other projects is not something you should rely on unless you force it.
In a Gradle multi-project build, how do you make one subproject depend on another subproject so it can use its classes and outputs?
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.
When :app declares implementation(project(':lib')), how does Gradle decide the order in which :lib and :app tasks run?
basics
~10 sBecause :app's compile classpath needs :lib's jar, Gradle automatically builds :lib first. The project dependency creates implicit task dependencies, so :lib:jar runs before :app:compileJava — you don't wire that ordering by hand.
How do you share test helper code (fixtures) between two Gradle modules so that one project's tests can reuse fixtures defined in another?
basics
~10 sApply the java-test-fixtures plugin to the producing module, put shared helpers in src/testFixtures/java, then in the consumer declare testImplementation(testFixtures(project(":lib"))).
How do you depend on a *specific* named configuration of another project in the same build, rather than its default API/runtime, and what does the syntax look like?
basics
~10 sUse the two-arg project notation: project(path: ':lib', configuration: 'someConfig'). The configuration name selects which producer configuration to consume instead of the default one.
When wiring one subproject onto another with project(...), what is the difference between declaring it with api(project(':lib')) versus implementation(project(':lib'))?
basics
~10 simplementation(project(":lib")) keeps :lib private to the consumer — downstream projects can't see it. api(project(":lib")) exposes :lib transitively to anyone depending on the consumer. api needs the java-library plugin.
In a Gradle composite build, what happens to a dependency on a published module when you include the producing build with includeBuild?
basics
~10 sGradle automatically substitutes the published module coordinates with the local included build's project. Instead of downloading the artifact from a repository, it builds and uses the local source.
What is a composite build in Gradle, and how do you wire one using includeBuild?
basics
~10 sA composite build combines otherwise independent Gradle builds into one. You wire it by adding includeBuild('../other-build') to settings.gradle.kts; Gradle then treats the included build as part of the current build.
What must the in-development plugin build declare so that a consumer including it can apply the plugin by its id?
basics
~10 sThe plugin build must apply the java-gradle-plugin plugin and declare the plugin id and implementationClass in a gradlePlugin { plugins { register(...) } } block. That generates the marker the consumer's id resolves against.
How do you run a task that lives in an included build from the command line in a Gradle composite build?
basics
~10 sPrefix the task path with the included build's name: ./gradlew :includedBuildName:some:task. The leading segment is the build name (its directory name unless overridden), not a project in the root build.
When automatic substitution in a composite build isn't enough, how do you declare an explicit substitution, and what is the syntax?
basics
~10 sUse a dependencySubstitution block on the includeBuild and call substitute(module("group:name")).using(project(":path")) to map a published module to a specific project in the included build.