# Structuring Multi-Project Builds

version 9.8.0-milestone-2

As your codebase grows, organizing it into multiple subprojects becomes essential for maintainability, performance, and reuse. Gradle supports this with 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 sample multi-project build that contains three subprojects:

The directory structure should look as follows:

    .
    ├── 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.

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

settings.gradle.kts

    include("sub-project-1", "sub-project-2", "sub-project-3")

settings.gradle

    include('sub-project-1', 'sub-project-2', 'sub-project-3')

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

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 shared build logic.

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

In either case, the `build-logic` and `buildSrc` folders are used to organize build logic.

Each approach has trade-offs. `buildSrc` is easier to get started with but less flexible. Composite builds require a bit more setup but scale better and align with Gradle’s long-term best practices for sharing build logic.

## Multi-Project Paths

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.

### 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 `sub-project-1`, `sub-project-2`, and `sub-project-3`.

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

In a multi-project build, you can run tasks for a specific subproject by using the task’s fully qualified name. This name combines the project path and the task name.

For example, to run the build task in `sub-project-1`, use `./gradlew :sub-project-1:build`. This ensures that only `sub-project-1’s `build` task is executed, rather than running build across the entire build.

You can use this pattern for any task. For example, to list all tasks available in `sub-project-3`, run `./gradlew :sub-project-3:tasks`.

## 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, if the project above had common build logic between `sub-project-1`, `sub-project-2` and `sub-project-3`, it could be structured as follows:

    .
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle(.kts)
    ├── buildSrc        (1)
    │   ├── build.gradle.kts
    │   └── src/main/*/shared-build-conventions.gradle(.kts)    (2)
    ├── sub-project-1
    │   └── build.gradle(.kts)              (3)
    ├── sub-project-2
    │   └── build.gradle(.kts)              (3)
    └── sub-project-3
        └── build.gradle(.kts)              (3)

1 | Gradle recognized `buildSrc` folder
2 | Contains common build logic from `sub-project-1`, `sub-project-2` and `sub-project-3`
3 | Applies `shared-build-conventions.gradle(.kts)`

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`.

Consult the Sharing Build Logic using `buildSrc` chapter to learn more.

## Composite Builds including `build-logic`

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

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 its own build script and settings file:

    .
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle(.kts)
    ├── build-logic         (1)
    │   ├── settings.gradle.kts
    │   └── conventions
    │       ├── build.gradle.kts
    │       └── src/main/kotlin/shared-build-conventions.gradle.kts (2)
    ├── sub-project-1
    │   └── build.gradle(.kts)              (3)
    ├── sub-project-2
    │   └── build.gradle(.kts)              (3)
    └── sub-project-3
        └── build.gradle(.kts)              (3)

1 | Separate Gradle build called `build-logic`
2 | Contains common build logic from `sub-project-1`, `sub-project-2` and `sub-project-3`
3 | Applies `shared-build-conventions.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

    include("sub-project-1", "sub-project-2", "sub-project-3")
    includeBuild("build-logic")

settings.gradle

    include('sub-project-1', 'sub-project-2', 'sub-project-3')
    includeBuild('build-logic')

There’s no reason that any of the subprojects in a multi-project build couldn’t themselves be composite builds. This allows teams to independently develop and test build logic or components, then include them in a larger build as needed. For example:

    .
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle(.kts)
    ├── build-logic             (1)
    │   ├── settings.gradle(.kts)
    │   └── conventions
    │       └── build.gradle(.kts)
    ├── project-1                   (2)
    │   ├── settings.gradle(.kts)
    │   ├── client
    │   │   └── build.gradle(.kts)
    │   └── server
    │       └── build.gradle(.kts)
    ├── project-2                   (3)
    │   ├── settings.gradle(.kts)
    │   └── lib
    │       └── build.gradle(.kts)
    └── project-3                   (4)
        ├── settings.gradle(.kts)
        ├── app-plugin
        │   └── build.gradle(.kts)
        ├── client-plugin
        │   └── build.gradle(.kts)
        └── server-plugin
            └── build.gradle(.kts)

1 | Separate Gradle build called `build-logic`
2 | Separate Gradle build called `project-1` with 2 of its own subproject
3 | Separate Gradle build called `project-2` with 1 of its own subproject
4 | Separate Gradle build called `project-3` with 3 of its own subprojects

In this setup, a team could work on `project-3` as an entirely independent build. Once their changes are complete, another team could test and validate those changes by integrating `project-3’s changes into the full root build.

Consult the Composite Builds chapter to learn more.

Next Step: Learn about the Gradle Build Lifecycle >>