Gradle
Gradle is one of the most widely used build tools in the JVM ecosystem. This article covers Gradle's origins, how it works, and how it differs from Maven.
Table of contents
Gradle is one of the most widely used build tools in the JVM ecosystem. This article covers Gradle's origins, how it works, and how it differs from Maven.
1. About Gradle
Hans Dockter started it in 2007 and shipped 1.0 in June 2012. The company Gradleware later renamed to Gradle Inc. License is Apache 2.0.
Build scripts (build.gradle) were originally a Groovy DSL. Kotlin DSL (build.gradle.kts) reached 1.0 in November 2018, and adoption grew quickly once Android Studio's new project default switched to Kotlin.
When Android's build tooling adopted Gradle (Android Studio's 2013 release), Gradle became the de facto standard across Java and Kotlin.
2. Core model
A Gradle build is a directed acyclic graph (DAG) of tasks. The build task depends on compileJava, which depends on processResources, and so on. Gradle resolves dependencies and runs them in the correct order.
Tasks declare inputs and outputs. When the input hash matches, Gradle pulls the result from cache. This mechanism is the primary way Gradle reduces build time.
3. Wrapper
gradlew (Unix) and gradlew.bat (Windows), along with gradle/wrapper/gradle-wrapper.properties, are committed to the repo. The properties file pins the Gradle version, and the first run downloads that version automatically. Builds run identically without Gradle preinstalled on the system.
# Windows
./gradlew.bat build
# macOS · Linux
./gradlew build
4. Daemon
Gradle runs a background daemon process to reuse JVM startup costs and caches. Enabled by default. The first run is slow; subsequent ones are short.
5. Build Cache · Configuration Cache
- Build cache — Stores task outputs as key-value pairs. Local cache is enabled by default; remote cache (a server) is optional.
- Configuration cache — Stores the result of the configuration phase so the next invocation can skip reconfiguration. After stabilizing across releases, it has been moving closer to the default in 9.x.
6. Multi-project
The root settings.gradle(.kts) declares which modules are included:
// settings.gradle.kts
rootProject.name = "myapp"
include("api", "common", "worker")
Each module gets its own build.gradle.kts, and internal dependencies are declared as implementation(project(":common")).
7. Other paths
| Tool | First release | Place |
|---|---|---|
| Apache Ant | 2000 | XML-based. Build steps written by hand. Dependency management is separate (Ivy). |
| Apache Maven | 2004 | XML (pom.xml). Convention-first with built-in dependency management. Still dominant in enterprise. |
| Gradle | 2012 (1.0) | DSL-based. Strong on incremental builds, caching, and daemon-driven build-time wins. |
| Bazel | 2015 (OSS) | OSS form of Google Blaze. Deterministic builds, remote execution. Far broader than JVM. |
Compared with Maven:
- Expression — XML tree vs DSL (code). DSL is flexible with conditionals and loops; XML is widely seen as plainer to read.
- Cache and incremental builds — Gradle treats input/output-based caching as first-class. Maven is weaker at automatically skipping unchanged modules in multi-module builds.
- Daemon — Only Gradle runs a daemon by default, cutting JVM startup overhead.
- Learning curve — Maven's strong conventions are formal, while Gradle's flexibility makes badly written builds harder to debug.
8. Common shapes
Basic commands:
./gradlew tasks # list all tasks
./gradlew :api:build # only that module
./gradlew test --tests "com.example.UserServiceTest"
./gradlew clean build --no-daemon
./gradlew dependencies # dependency tree
./gradlew --refresh-dependencies # ignore cache and re-resolve
build.gradle.kts (Spring Boot, abbreviated):
plugins {
java
id("org.springframework.boot") version "3.3.0"
id("io.spring.dependency-management") version "1.1.6"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
repositories { mavenCentral() }
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.test { useJUnitPlatform() }
Frequent options in gradle.properties:
org.gradle.jvmargs=-Xmx2g
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
9. Common pitfalls
Compatibility matrix — version compatibility across Gradle, plugins, and JDKs is tight. Check the official compatibility table first when builds break.
Wrapper partially committed — won't run on other machines. Commit all four files together: gradlew, gradlew.bat, and gradle/wrapper/*.
Imperative code vs configuration cache — heavy imperative code in build.gradle(.kts) clashes with the configuration cache. Stick to the lazy APIs the official docs recommend (tasks.register, Provider).
Daemon OOM — set a sensible heap with org.gradle.jvmargs, or run CI with --no-daemon to disable the daemon entirely.
Mixed Groovy and Kotlin DSL — combining them across modules makes code sharing painful. Pick one DSL per repo.
Closing thoughts
Gradle's real value lies in incremental builds, build cache, and the daemon working together. In large multi-module setups, build times shorten visibly compared to Maven. Commit all four wrapper files for identical builds across machines. Following the lazy APIs of the configuration cache pays off long-term.
Next
- editor-setup
- linting-formatting
References include the official Gradle docs, Gradle GitHub, Gradle Kotlin DSL Primer, Compatibility Matrix, Apache Maven docs, Gradle Build Cache guide, and the Gradle blog.
More in tools
All in this category →Related posts
Android App Build — APK · AAB · Signing
Building an Android app, regardless of the tool, eventually goes through similar steps. Compile sources, bundle resources, convert to DEX, and sign. The result is an APK or an AAB. This post walks through that flow, the…
Spring Multi-Module (Gradle)
When several Spring applications live in a single repository, we have to settle the location of shared code, the build unit, and the direction of dependencies. Gradle's multi-project build is the standard tool for handl…
The shape of Java 21
First released in 1995, Java has lived for nearly 30 years. This post lays out Java's flow, the LTS cycle, and a few features in Java 21 that carry real weight, all on a factual basis. We also briefly touch on neighbors…