Speeding Up Gradle Sync in Multi-Module Spring Boot Projects
TL;DR: Switching from the Spring Dependency plugin to Gradle Platforms reduced Gradle Sync time from ∼4-15 minutes to ∼1 minute.
In a Spring Boot Java project running Gradle as the build tool, we have structured the code into ∼400 modules according to a specification made in collaboration with the domain experts. This domain-driven structure helped define clear functional boundaries and made the architecture easier to manage across teams.
Due to the large number of modules, we experienced significant Gradle Sync performance issues. Initially, syncing the modules took ∼1 minute, but with a later upgrade of the underlying platform, it increased to ∼15 minutes. Using a dedicated workspace free of antivirus scanning, we were able to reduce the Sync time to ∼4 minutes, though it could still spike up to around 10 minutes. Switching branches often cost developers ∼4 minutes each time, slowing down their workflow.
We discovered that the problem originated in an underlying plugin we were using for Spring dependencies. Specifically, the setup looked something like the following:
plugins {
id 'io.spring.dependency-management' version '1.1.2'
}
subprojects {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:3.5.6"
}
}
}
This applies the dependency management plugin to all subprojects and ensures the correct versions using the BOM. Effectively we could write:
implementation 'org.hibernate.orm:hibernate-core' // version comes from BOM
instead of:
implementation 'org.hibernate.orm:hibernate-core:6.3.0.Final' // explicit version
This is important because we want to ensure library versions across different modules remain the same.
The problem was in the overhead of the Spring Dependency plugin, which spent ∼0.5 seconds resolving dependencies for each module. This totaled ∼2.5 minutes of dependency checking time. It did not seem like it parallelized this process in Gradle, even with parallel builds activated.
We solved this by switching to Gradle platforms. This solves the same problem while leveraging Gradle's built-in version alignment and caching, which the plugin lacks. The setup was changed to the following:
subprojects {
dependencies {
implementation(platform('org.springframework.boot:spring-boot-dependencies:3.5.6'))
testImplementation(platform('org.springframework.boot:spring-boot-dependencies:3.5.6'))
annotationProcessor(platform('org.springframework.boot:spring-boot-dependencies:3.5.6'))
}
}
This replaces the Spring Dependency plugin directly by only exposing the BOM to the Gradle platforms plugin. We observed minor version changes in several libraries. One library changed from 10.0.4
to 10.0.3
. These were considered acceptable, as we could always add version constraints if a specific version was required.
Gradle Sync is now consistently fast, saving developers several minutes each time they switch branches. This has made working in the project much more enjoyable, as the previous delays were a significant source of frustration. I hope this post helps anyone facing the same issue in their projects.