# Multi-Project Build Basics

version 8.14.4-20260121040326+0000

Gradle supports multi-project builds.

While some small projects and monolithic applications may contain a single build file and source tree, it is often more common for a project to have been split into smaller, interdependent modules. The word "interdependent" is vital, as you typically want to link the many modules together through a single build.

Gradle supports this scenario through multi-project builds. This is sometimes referred to as a multi-module project. Gradle refers to modules as subprojects.

A multi-project build consists of one root project and one or more subprojects.

## Multi-Project structure

The following represents the structure of a multi-project build that contains three subprojects:

The directory structure should look as follows:

    ├── .gradle
    │   └── ⋮
    ├── gradle
    │   ├── libs.versions.toml
    │   └── wrapper
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle.kts (1)
    ├── sub-project-1
    │   └── build.gradle.kts    (2)
    ├── sub-project-2
    │   └── build.gradle.kts    (2)
    └── sub-project-3
        └── build.gradle.kts    (2)

1 | The `settings.gradle.kts` file should include all subprojects.
2 | Each subproject should have its own `build.gradle.kts` file.

## Multi-Project standards

The Gradle community has two standards for multi-project build structures:

1. Multi-Project Builds using buildSrc - where `buildSrc` is a subproject-like directory at the Gradle project root containing all the build logic.

2. Composite Builds - a build that includes other builds where `build-logic` is a build directory at the Gradle project root containing reusable build logic.

### 1. Multi-Project Builds using `buildSrc`

Multi-project builds allow you to organize projects with many modules, wire dependencies between those modules, and easily share common build logic amongst them.

For example, a build that has many modules called `mobile-app`, `web-app`, `api`, `lib`, and `documentation` could be structured as follows:

    .
    ├── gradle
    ├── gradlew
    ├── settings.gradle.kts
    ├── buildSrc
    │   ├── build.gradle.kts
    │   └── src/main/kotlin/shared-build-conventions.gradle.kts
    ├── mobile-app
    │   └── build.gradle.kts
    ├── web-app
    │   └── build.gradle.kts
    ├── api
    │   └── build.gradle.kts
    ├── lib
    │   └── build.gradle.kts
    └── documentation
        └── build.gradle.kts

The modules will have dependencies between them such as `web-app` and `mobile-app` depending on `lib`. This means that in order for Gradle to build `web-app` or `mobile-app`, it must build `lib` first.

In this example, the root settings file will look as follows:

settings.gradle.kts

    include("mobile-app", "web-app", "api", "lib", "documentation")

settings.gradle

    include("mobile-app", "web-app", "api", "lib", "documentation")

| The order in which the subprojects (modules) are included does not matter.

The `buildSrc` directory is automatically recognized by Gradle. It is a good place to define and maintain shared configuration or imperative build logic, such as custom tasks or plugins.

`buildSrc` is automatically included in your build as a special subproject if a `build.gradle(.kts)` file is found under `buildSrc`.

If the `java` plugin is applied to the `buildSrc` project, the compiled code from `buildSrc/src/main/java` is put in the classpath of the root build script, making it available to any subproject (`web-app`, `mobile-app`, `lib`, etc…​) in the build.

Consult how to declare dependencies between subprojects to learn more.

### 2. Composite Builds

Composite Builds, also referred to as included builds, are best for sharing logic between builds (not subprojects) or isolating access to shared build logic (i.e., convention plugins).

Let’s take the previous example. The logic in `buildSrc` has been turned into a project that contains plugins and can be published and worked on independently of the root project build.

The plugin is moved to its own build called `build-logic` with a build script and settings file:

    .
    ├── gradle
    ├── gradlew
    ├── settings.gradle.kts
    ├── build-logic
    │   ├── settings.gradle.kts
    │   └── conventions
    │       ├── build.gradle.kts
    │       └── src/main/kotlin/shared-build-conventions.gradle.kts
    ├── mobile-app
    │   └── build.gradle.kts
    ├── web-app
    │   └── build.gradle.kts
    ├── api
    │   └── build.gradle.kts
    ├── lib
    │   └── build.gradle.kts
    └── documentation
        └── build.gradle.kts

| The fact that `build-logic` is located in a subdirectory of the root project is irrelevant. The folder could be located outside the root project if desired.

The root settings file includes the entire `build-logic` build:

settings.gradle.kts

    pluginManagement {
        includeBuild("build-logic")
    }
    include("mobile-app", "web-app", "api", "lib", "documentation")

Consult how to create composite builds with `includeBuild` to learn more.

## Multi-Project path

A project path has the following pattern: it starts with an optional colon, which denotes the root project.

The root project, `:`, is the only project in a path not specified by its name.

The rest of a project path is a colon-separated sequence of project names, where the next project is a subproject of the previous project:

    :sub-project-1

You can see the project paths when running `gradle projects`:

    ------------------------------------------------------------
    Root project 'project'
    ------------------------------------------------------------

    Root project 'project'
    +--- Project ':sub-project-1'
    \--- Project ':sub-project-2'

Project paths usually reflect the filesystem layout, but there are exceptions. Most notably for composite builds.

## Identifying project structure

You can use the `gradle projects` command to identify the project structure.

As an example, let’s use a multi-project build with the following structure:

    $ gradle -q projects

    Projects:

    ------------------------------------------------------------
    Root project 'multiproject'
    ------------------------------------------------------------

    Root project 'multiproject'
    +--- Project ':api'
    +--- Project ':services'
    |    +--- Project ':services:shared'
    |    \--- Project ':services:webservice'
    \--- Project ':shared'

    To see a list of the tasks of a project, run gradle <project-path>:tasks
    For example, try running gradle :api:tasks

Multi-project builds are collections of tasks you can run. The difference is that you may want to control which project’s tasks get executed.

The following sections will cover your two options for executing tasks in a multi-project build.

### Executing tasks by name

The command `gradle test` will execute the `test` task in any subprojects relative to the current working directory that has that task.

If you run the command from the root project directory, you will run `test` in api, shared, services:shared and services:webservice.

If you run the command from the services project directory, you will only execute the task in services:shared and services:webservice.

The basic rule behind Gradle’s behavior is to execute all tasks down the hierarchy with this name. And complain if there is no such task found in any of the subprojects traversed.

| Some task selectors, like `help` or `dependencies`, will only run the task on the project they are invoked on and not on all the subprojects to reduce the amount of information printed on the screen.

### Executing tasks by fully qualified name

You can use a task’s fully qualified name to execute a specific task in a particular subproject. For example: `gradle :services:webservice:build` will run the `build` task of the webservice subproject.

The fully qualified name of a task is its project path plus the task name.

This approach works for any task, so if you want to know what tasks are in a particular subproject, use the `tasks` task, e.g. `gradle :services:webservice:tasks`.

## Multi-Project building and testing

The `build` task is typically used to compile, test, and check a single project.

In multi-project builds, you may often want to do all of these tasks across various projects. The `buildNeeded` and `buildDependents` tasks can help with this.

In this example, the `:services:person-service` project depends on both the `:api` and `:shared` projects. The `:api` project also depends on the `:shared` project.

Assuming you are working on a single project, the `:api` project, you have been making changes but have not built the entire project since performing a `clean`. You want to build any necessary supporting JARs but only perform code quality and unit tests on the parts of the project you have changed.

The `build` task does this:

    $ gradle :api:build
    > Task :shared:compileJava
    > Task :shared:processResources
    > Task :shared:classes
    > Task :shared:jar
    > Task :api:compileJava
    > Task :api:processResources
    > Task :api:classes
    > Task :api:jar
    > Task :api:assemble
    > Task :api:compileTestJava
    > Task :api:processTestResources
    > Task :api:testClasses
    > Task :api:test
    > Task :api:check
    > Task :api:build

    BUILD SUCCESSFUL in 0s

If you have just gotten the latest version of the source from your version control system, which included changes in other projects that `:api` depends on, you might want to build all the projects you depend on AND test them too.

The `buildNeeded` task builds AND tests all the projects from the project dependencies of the `testRuntime` configuration:

    $ gradle :api:buildNeeded
    > Task :shared:compileJava
    > Task :shared:processResources
    > Task :shared:classes
    > Task :shared:jar
    > Task :api:compileJava
    > Task :api:processResources
    > Task :api:classes
    > Task :api:jar
    > Task :api:assemble
    > Task :api:compileTestJava
    > Task :api:processTestResources
    > Task :api:testClasses
    > Task :api:test
    > Task :api:check
    > Task :api:build
    > Task :shared:assemble
    > Task :shared:compileTestJava
    > Task :shared:processTestResources
    > Task :shared:testClasses
    > Task :shared:test
    > Task :shared:check
    > Task :shared:build
    > Task :shared:buildNeeded
    > Task :api:buildNeeded

    BUILD SUCCESSFUL in 0s

You may want to refactor some part of the `:api` project used in other projects. If you make these changes, testing only the `:api` project is insufficient. You must test all projects that depend on the `:api` project.

The `buildDependents` task tests ALL the projects that have a project dependency (in the testRuntime configuration) on the specified project:

    $ gradle :api:buildDependents
    > Task :shared:compileJava
    > Task :shared:processResources
    > Task :shared:classes
    > Task :shared:jar
    > Task :api:compileJava
    > Task :api:processResources
    > Task :api:classes
    > Task :api:jar
    > Task :api:assemble
    > Task :api:compileTestJava
    > Task :api:processTestResources
    > Task :api:testClasses
    > Task :api:test
    > Task :api:check
    > Task :api:build
    > Task :services:person-service:compileJava
    > Task :services:person-service:processResources
    > Task :services:person-service:classes
    > Task :services:person-service:jar
    > Task :services:person-service:assemble
    > Task :services:person-service:compileTestJava
    > Task :services:person-service:processTestResources
    > Task :services:person-service:testClasses
    > Task :services:person-service:test
    > Task :services:person-service:check
    > Task :services:person-service:build
    > Task :services:person-service:buildDependents
    > Task :api:buildDependents

    BUILD SUCCESSFUL in 0s

Finally, you can build and test everything in all projects. Any task you run in the root project folder will cause that same-named task to be run on all the children.

You can run `gradle build` to build and test ALL projects.

Consult the Structuring Builds chapter to learn more.

Next Step: Learn about the Gradle Build Lifecycle >>