Multi-Project Builds in Gradle

Introduction

Large codebases split into modules—shared libraries, APIs, and apps. Gradle links them in settings.gradle and wires dependencies with project(':module'). One ./gradlew build at the root compiles everything in the right order. This chapter builds a common + app layout and compares it to Maven multi-module projects.

Prerequisites

Layout

text
demo-monorepo/
  settings.gradle
  build.gradle              # optional root config
  common/
    build.gradle
    src/main/java/...
  app/
    build.gradle
    src/main/java/...

settings.gradle

gradle
rootProject.name = 'demo-monorepo'
include 'common', 'app'

Gradle expects folders common/ and app/ with build.gradle each.

Root build.gradle (Shared Defaults)

subprojects { } runs for common and app. The root project itself may have no sources.

common Library Module

common/build.gradle:

gradle
plugins {
    id 'java-library'
}
 
dependencies {
    api 'com.google.code.gson:gson:2.11.0'
}

common/src/main/java/com/example/common/Greeting.java:

java
package com.example.common;
 
public final class Greeting {
 
    private Greeting() {}
 
    public static String hello(String name) {
        return "Hello, " + name;
    }
}

java-library + api exposes Gson to consumers if they use types from Gson in public API (here only strings—implementation would also work).

app Application Module

app/build.gradle:

gradle
plugins {
    id 'application'
}
 
dependencies {
    implementation project(':common')
}
 
application {
    mainClass = 'com.example.app.Main'
}

app/src/main/java/com/example/app/Main.java:

java
package com.example.app;
 
import com.example.common.Greeting;
 
public class Main {
 
    public static void main(String[] args) {
        System.out.println(Greeting.hello("Gradle"));
    }
}

Build and Run from Root

bash
./gradlew build
./gradlew :app:run

Task path syntax: :project:task (:app:run, :common:test).

List all projects:

bash
./gradlew projects

Project Dependency Direction

text
app  ──implementation──>  common

Never create cycles (common must not depend on app). Gradle fails the build on circular project references.

Maven Comparison

MavenGradle
<modules> in parent POMinclude in settings.gradle
<parent> inheritancesubprojects / allprojects blocks
Inter-module dep<dependency><artifactId>common</artifactId></dependency>
Build from rootmvn install

Version Catalog in Monorepos

Place gradle/libs.versions.toml at root; subprojects use libs.gson—keeps versions consistent (see dependency chapter).

Mini Example: Task Only on One Module

gradle
// app/build.gradle
tasks.register('showMain') {
    doLast {
        println "Main class: " + application.mainClass.get()
    }
}
bash
./gradlew :app:showMain

FAQ

Root project has no src/?

Normal—root aggregates configuration; modules hold code.

Project with path ':common' not found?

Check include 'common' and folder name spelling.

Publish one module only?

./gradlew :common:publishToMavenLocal with maven-publish on that subproject.

IDEA import?

Open the root folder containing settings.gradle—IDEA loads all modules.

What comes next?

Repositories and publishing.