If you are building a software of a certain size with Gradle, you have two basic structuring mechanisms. First, this chapter describes how to structure your software project using a Gradle multi-project. In this documentation, we consider this to be a single software component which is structured internally. Second, you may regard your software as a software product that is composed of multiple software components where each component is represented by a separate Gradle build. This is described in detail in the chapter on structuring software products with Gradle

Creating a multi-project build

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

A basic multi-project build contains a root project and a single subproject. This is a structure of a multi-project build that contains a single subproject called app:

Project layout
.
├── app
│   ...
│   └── build.gradle.kts
└── settings.gradle.kts
Project layout
.
├── 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.

Note that the root project does not have a Gradle build file, only a settings file that defines the subprojects to include.

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 in the app directory.

We can view the structure of a multi-project build by running the gradle projects command.

> gradle -q 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

Let’s say the app subproject is a Java application by applying the application plugin and configuring the main class:

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!");
    }
}

We can then run the application by executing the run task from the application plugin.

> gradle -q run
Hello, world!

And that’s how simple it is to create a basic multi-project build.

Adding subprojects

Let’s say we want to 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 for the new subproject in the lib/ subdirectory of the project:

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

Next, will explore how build logic can be shared between subprojects and how subprojects can depend on one another.

Naming recommendations

As your project grows, naming and consistency gets 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 keep track of which project belongs to what folders.

  2. Use kebab case formatting for all project names: A kebab case formatting is when all letters lowercase, words separated with a dash (‘-’) character (e.g.kebab-case-formatting). This is already the de-facto pattern for many large projects. Besides, Gradle supports name abbreviation for kebab case names.

  3. Define the root project name in the settings file: The ´rootProject.name´ effectively assigns a name to the build as a whole, which is 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 to any directory). If the root project name is not set and it is checked out to a root of a file system (e.g. / or C:\), the name will be generated randomly.