Spring Boot
Gradle Setup
Gradle is Spring Boot's second officially supported build tool — faster than Maven due to incremental builds and build caching, with a concise Groovy or Kotlin DSL instead of XML. Understanding Gradle's Spring Boot setup — the plugins, dependency configurations, tasks, and the Gradle wrapper — gives you a modern, high-performance build pipeline.
Spring Boot and Gradle
Gradle builds are defined in build.gradle (Groovy DSL) or build.gradle.kts (Kotlin DSL). Spring Boot integrates with Gradle through two plugins: the Spring Boot plugin which provides the bootRun task and creates executable JARs, and the Spring Dependency Management plugin which imports Spring Boot's BOM to manage dependency versions — the Gradle equivalent of Maven's parent POM.
Gradle's key advantages over Maven for Spring Boot projects are incremental compilation (only recompiles changed files), build caching (reuses task outputs across builds), parallel task execution, and a concise, programmable build script instead of XML. For large projects, Gradle builds are typically 2-5x faster than equivalent Maven builds.
build.gradle — Groovy DSL
The Groovy DSL is the traditional Gradle format — concise, widely used, and fully supported by all Spring Boot tooling.
groovy
// build.gradle (Groovy DSL)
plugins {
// Spring Boot plugin — provides bootRun task, creates executable JAR:
id 'org.springframework.boot' version '3.2.4'
// Dependency management — imports Spring Boot BOM (manages all versions):
id 'io.spring.dependency-management' version '1.1.4'
// Java compilation:
id 'java'
}
group = 'com.example'
version = '1.0.0-SNAPSHOT'
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
// Enable annotation processing (required for Lombok, MapStruct, etc.):
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
// Spring Boot starters — no versions needed (managed by BOM):
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Database:
runtimeOnly 'com.mysql:mysql-connector-j'
runtimeOnly 'com.h2database:h2'
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'
// Lombok — compile-time only:
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// DevTools — development only, excluded from production JAR:
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// Testing:
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform() // required for JUnit 5
}build.gradle.kts — Kotlin DSL
The Kotlin DSL provides type safety, IDE auto-completion, and compile-time validation for your build script. It is the recommended format for new Gradle projects.
kotlin
// build.gradle.kts (Kotlin DSL)
plugins {
id("org.springframework.boot") version "3.2.4"
id("io.spring.dependency-management") version "1.1.4"
java
}
group = "com.example"
version = "1.0.0-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-actuator")
runtimeOnly("com.mysql:mysql-connector-j")
runtimeOnly("com.h2database:h2")
implementation("org.flywaydb:flyway-core")
implementation("org.flywaydb:flyway-mysql")
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.withType<Test> {
useJUnitPlatform()
}Gradle Dependency Configurations
Gradle uses named configurations instead of Maven's scopes. Each configuration controls which classpath a dependency appears on and whether it is included in the packaged JAR.
groovy
dependencies {
// implementation — compile and runtime classpath, included in JAR:
// Use for: all Spring Boot starters, your main dependencies
// NOT exposed to consumers of this library (unlike 'api')
implementation 'org.springframework.boot:spring-boot-starter-web'
// api — like implementation but also exposed to consumers:
// Use for: library projects where consumers need your dependency's types
// Requires the 'java-library' plugin
// api 'com.example:shared-models:1.0.0'
// runtimeOnly — runtime classpath only, NOT compile classpath:
// Included in JAR. Use for: JDBC drivers, database connectors
runtimeOnly 'com.mysql:mysql-connector-j'
// compileOnly — compile classpath only, NOT runtime:
// NOT included in JAR. Use for: Lombok (annotation processor only)
compileOnly 'org.projectlombok:lombok'
// annotationProcessor — annotation processor classpath:
// Runs during compilation. Use for: Lombok, MapStruct, Spring processors
annotationProcessor 'org.projectlombok:lombok'
// developmentOnly — Spring Boot's custom config for dev-only dependencies:
// Excluded from bootJar/bootWar. Use for: DevTools
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// testImplementation — test compile and runtime classpath:
// NOT in production JAR. Use for: JUnit, Mockito, Spring Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// testRuntimeOnly — test runtime only:
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// testCompileOnly — test compile only:
// testCompileOnly 'org.projectlombok:lombok'
// testAnnotationProcessor — annotation processing for tests:
// testAnnotationProcessor 'org.projectlombok:lombok'
}Essential Gradle Tasks
Gradle tasks are the equivalent of Maven goals. The Gradle wrapper (gradlew) is used instead of a global Gradle installation to ensure consistent versions.
Shell
# The Gradle wrapper — always use this:
# Unix/macOS:
./gradlew <task>
# Windows:
gradlew.bat <task>
# ── DEVELOPMENT ──────────────────────────────────────────────────────
# Run the application:
./gradlew bootRun
# Run with a specific profile:
./gradlew bootRun --args='--spring.profiles.active=dev'
# Run with multiple arguments:
./gradlew bootRun --args='--spring.profiles.active=dev --server.port=9090'
# ── BUILDING ──────────────────────────────────────────────────────────
# Compile source code:
./gradlew compileJava
# Run tests:
./gradlew test
# Build the executable JAR (runs tests first):
./gradlew build
# Build without running tests:
./gradlew build -x test
# Build the executable JAR only (no tests, no other checks):
./gradlew bootJar
# Clean build outputs:
./gradlew clean
# Clean and build:
./gradlew clean build
# ── RUNNING THE JAR ───────────────────────────────────────────────────
# Run the packaged JAR:
java -jar build/libs/myapp-1.0.0-SNAPSHOT.jar
# ── DEPENDENCY MANAGEMENT ─────────────────────────────────────────────
# Show full dependency tree:
./gradlew dependencies
# Show dependencies for a specific configuration:
./gradlew dependencies --configuration runtimeClasspath
# Show why a specific dependency is included:
./gradlew dependencyInsight --dependency jackson-databind
# Check for dependency updates (requires ben-manes plugin):
./gradlew dependencyUpdates
# ── DIAGNOSTICS ───────────────────────────────────────────────────────
# List all available tasks:
./gradlew tasks
# List all tasks including subproject tasks:
./gradlew tasks --all
# Show detailed task information:
./gradlew help --task bootRun
# Run with verbose output:
./gradlew build --info
# Run with debug output:
./gradlew build --debug
# Profile the build (generates HTML report):
./gradlew build --profileOverriding Managed Versions
The Spring Dependency Management plugin manages versions through the imported BOM. Override specific versions by either using ext properties or direct version declarations.
groovy
// Groovy DSL — override managed versions:
ext {
// Override Spring Boot's managed versions:
set('jackson-bom.version', '2.16.1')
set('hibernate.version', '6.4.1.Final')
set('mockito.version', '5.8.0')
set('testcontainers.version', '1.19.3')
set('flyway.version', '10.3.0')
}
// OR use dependencyManagement block directly:
dependencyManagement {
imports {
mavenBom("org.testcontainers:testcontainers-bom:1.19.3")
}
dependencies {
// Override a specific dependency version:
dependency 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
}
}
// Add a dependency NOT in the BOM — specify version explicitly:
dependencies {
implementation 'com.auth0:java-jwt:4.4.0' // not in Spring Boot BOM
implementation 'io.jsonwebtoken:jjwt-api:0.12.3' // not in Spring Boot BOM
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
}
// Kotlin DSL — override managed versions:
extra["jackson-bom.version"] = "2.16.1"
extra["hibernate.version"] = "6.4.1.Final"
extra["testcontainers.version"] = "1.19.3"Gradle Wrapper
The Gradle wrapper ensures every developer and CI server uses exactly the same Gradle version — no global Gradle installation required.
Shell
# Gradle wrapper files in every generated Spring Boot project:
# gradlew ← shell script (Unix/macOS/Linux)
# gradlew.bat ← batch script (Windows)
# gradle/wrapper/
# gradle-wrapper.properties ← specifies Gradle version
# gradle-wrapper.jar ← bootstrap JAR
# gradle/wrapper/gradle-wrapper.properties:
# distributionBase=GRADLE_USER_HOME
# distributionPath=wrapper/dists
# distributionUrl=https://services.gradle.org/distributions/gradle-8.6-bin.zip
# zipStoreBase=GRADLE_USER_HOME
# zipStorePath=wrapper/dists
# Always commit wrapper files to version control:
git add gradlew gradlew.bat gradle/
git commit -m "Add Gradle wrapper"
# Make executable after git clone:
chmod +x gradlew
# Update the wrapper to a specific Gradle version:
./gradlew wrapper --gradle-version=8.7
# Verify wrapper version:
./gradlew --version
# Gradle 8.6
# JVM: 21 (Eclipse Adoptium)
# Add Gradle wrapper to an existing project:
gradle wrapper --gradle-version=8.6Gradle Build Optimization
Gradle has several features that dramatically speed up builds — incremental compilation, build caching, parallel execution, and the Gradle daemon. These are all enabled with simple configuration.
application.properties
# gradle.properties — project-level Gradle settings:
# (place in project root alongside build.gradle)
# Enable parallel task execution (multiple projects built simultaneously):
org.gradle.parallel=true
# Enable the Gradle build cache (reuse task outputs from previous builds):
org.gradle.caching=true
# Increase JVM heap for large projects:
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError
# Enable configuration cache (caches the build configuration phase):
org.gradle.configuration-cache=true
# Enable file system watching (faster incremental builds):
org.gradle.vfs.watch=true
# Gradle daemon — keeps Gradle process alive between builds (default: true):
org.gradle.daemon=true
org.gradle.daemon.idletimeout=3600000 # keep alive for 1 hour
# Spring Boot specific properties:
spring.profiles.active=dev # default profile when using bootRun
# ~/.gradle/gradle.properties — user-level settings (all projects):
# org.gradle.parallel=true
# org.gradle.caching=true
# org.gradle.daemon=true
# Check if build cache is working:
./gradlew build
# > Task :compileJava UP-TO-DATE ← using cached result
# > Task :test UP-TO-DATE ← skipped, inputs unchanged
# Clean Gradle caches if builds behave unexpectedly:
./gradlew clean
rm -rf ~/.gradle/caches/build-cache-* # clear build cache
./gradlew --stop # stop all running daemons