# Structuring Projects with Gradle

version 8.10.2

It is important to structure your Gradle project to optimize build performance. A multi-project build is the standard in Gradle.

A multi-project build consists of one root project and one or more subprojects. Gradle can build the root project and any number of the subprojects in a single execution.

## Project locations

Multi-project builds contain a single root project in a directory that Gradle views as the root path: `.`.

Subprojects are located physically under the root path: `./subproject`.

A subproject has a path, which denotes the position of that subproject in the multi-project build. In most cases, the project path is consistent with its location in the file system.

The project structure is created in the `settings.gradle(.kts)` file. The settings file must be present in the root directory.

## A simple multi-project build

Let’s look at a basic multi-project build example that contains a root project and a single subproject.

The root project is called `basic-multiproject`, located somewhere on your machine. From Gradle’s perspective, the root is the top-level directory `.`.

The project contains a single subproject called `./app`:

    .
    ├── app
    │   ...
    │   └── build.gradle.kts
    └── settings.gradle.kts

    .
    ├── app
    │   ...
    │   └── build.gradle
    └── settings.gradle

This is the recommended project structure for starting any Gradle project. The build init plugin also generates skeleton projects that follow this structure - a root project with a single subproject:

The `settings.gradle(.kts)` file describes the project structure to Gradle:

settings.gradle.kts

    rootProject.name = "basic-multiproject"
    include("app")

settings.gradle

    rootProject.name = 'basic-multiproject'
    include 'app'

In this case, Gradle will look for a build file for the `app` subproject in the `./app` directory.

You can view the structure of a multi-project build by running the `projects` command:

    $ ./gradlew -q projects

    Projects:

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

    Root project 'basic-multiproject'
    \--- Project ':app'

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

In this example, the `app` subproject is a Java application that applies the application plugin and configures the main class. The application prints `Hello World` to the console:

app/build.gradle.kts

    plugins {
        id("application")
    }

    application {
        mainClass = "com.example.Hello"
    }

app/build.gradle

    plugins {
        id 'application'
    }

    application {
        mainClass = 'com.example.Hello'
    }

app/src/main/java/com/example/Hello.java

    package com.example;

    public class Hello {
        public static void main(String[] args) {
            System.out.println("Hello, world!");
        }
    }

You can run the application by executing the `run` task from the application plugin in the project root:

    $ ./gradlew -q run
    Hello, world!

## Adding a subproject

In the settings file, you can use the `include` method to add another subproject to the root project:

settings.gradle.kts

    include("project1", "project2:child1", "project3:child1")

settings.gradle

    include 'project1', 'project2:child1', 'project3:child1'

The `include` method takes project paths as arguments. The project path is assumed to be equal to the relative physical file system path. For example, a path `services:api` is mapped by default to a folder `./services/api` (relative to the project root `.`).

More examples of how to work with the project path can be found in the DSL documentation of Settings.include(java.lang.String[]).

Let’s add another subproject called `lib` to the previously created project.

All we need to do is add another `include` statement in the root settings file:

settings.gradle.kts

    rootProject.name = "basic-multiproject"
    include("app")
    include("lib")

settings.gradle

    rootProject.name = 'basic-multiproject'
    include 'app'
    include 'lib'

Gradle will then look for the build file of the new `lib` subproject in the `./lib/` directory:

    .
    ├── app
    │   ...
    │   └── build.gradle.kts
    ├── lib
    │   ...
    │   └── build.gradle.kts
    └── settings.gradle.kts

    .
    ├── app
    │   ...
    │   └── build.gradle
    ├── lib
    │   ...
    │   └── build.gradle
    └── settings.gradle

## Project Descriptors

To further describe the project architecture to Gradle, the settings file provides project descriptors.

You can modify these descriptors in the settings file at any time.

To access a descriptor, you can:

settings.gradle.kts

    include("project-a")
    println(rootProject.name)
    println(project(":project-a").name)

settings.gradle

    include('project-a')
    println rootProject.name
    println project(':project-a').name

Using this descriptor, you can change the name, project directory, and build file of a project:

settings.gradle.kts

    rootProject.name = "main"
    include("project-a")
    project(":project-a").projectDir = file("custom/my-project-a")
    project(":project-a").buildFileName = "project-a.gradle.kts"

settings.gradle

    rootProject.name = 'main'
    include('project-a')
    project(':project-a').projectDir = file('custom/my-project-a')
    project(':project-a').buildFileName = 'project-a.gradle'

Consult the ProjectDescriptor class in the API documentation for more information.

## Modifying a subproject path

Let’s take a hypothetical project with the following structure:

    .
    ├── app
    │   ...
    │   └── build.gradle.kts
    ├── subs // Gradle may see this as a subproject
    │   └── web // Gradle may see this as a subproject
    │       └── my-web-module // Intended subproject
    │           ...
    │           └── build.gradle.kts
    └── settings.gradle.kts

    .
    ├── app
    │   ...
    │   └── build.gradle
    ├── subs // Gradle may see this as a subproject
    │   └── web // Gradle may see this as a subproject
    │       └── my-web-module // Intended subproject
    │           ...
    │           └── build.gradle
    └── settings.gradle

If your `settings.gradle(.kts)` looks like this:

    include(':subs:web:my-web-module')

Gradle sees a subproject with a logical project name of `:subs:web:my-web-module` and two, possibly unintentional, other subprojects logically named `:subs` and `:subs:web`. This can lead to phantom build directories, especially when using `allprojects{}` or `subproject{}`.

To avoid this, you can use:

    include(':my-web-module')
    project(':my-web-module').projectDir = "subs/web/my-web-module"

So that you only end up with a single subproject named `:my-web-module`.

So, while the physical project layout is the same, the logical results are different.

## Naming recommendations

As your project grows, naming and consistency get increasingly more important. To keep your builds maintainable, we recommend the following:

1. Keep default project names for subprojects: It is possible to configure custom project names in the settings file. However, it’s an unnecessary extra effort for the developers to track which projects belong to what folders.

2. Use lower case hyphenation for all project names: All letters are lowercase, and words are separated with a dash (`-`) character.

3. Define the root project name in the settings file: The `rootProject.name` effectively assigns a name to the build, used in reports like Build Scans. If the root project name is not set, the name will be the container directory name, which can be unstable (i.e., you can check out your project in any directory). The name will be generated randomly if the root project name is not set and checked out to a file system’s root (e.g., `/` or `C:\`).