Gradle — Build.gradle, Kotlin DSL, Tasks, Dependencies, and the Gradle Wrapper
In this tutorial, you will learn about Gradle. We cover key concepts, practical examples, and best practices to help you master this topic.
Gradle is a build automation tool that uses a Groovy or Kotlin DSL for declarative configuration and incremental builds. Unlike Maven's rigid lifecycle, Gradle uses a directed acyclic graph (DAG) of tasks — you define tasks and their dependencies, and Gradle executes them in the correct order, skipping up-to-date tasks.
What You'll Learn
- build.gradle.kts vs build.gradle
- Tasks: defining, configuring, and ordering
- Dependency management: repositories, configurations
- The Gradle wrapper for reproducible builds
Why It Matters
Gradle is the default build tool for Android and is increasingly popular for Java projects. Its incremental build system, build cache, and flexible DSL make it faster and more expressive than Maven for complex builds.
Real-World Use
Android builds, Spring Boot projects (Spring Initializr now offers Gradle), and large multi-module projects benefit from Gradle's performance advantages.
Build Script Basics
Kotlin DSL (build.gradle.kts)
plugins {
java
application
}
group = "com.example"
version = "1.0.0"
application {
mainClass.set("com.example.Main")
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.apache.commons:commons-lang3:3.13.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
tasks.test {
useJUnitPlatform()
}
Groovy DSL (build.gradle)
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0.0'
application {
mainClass = 'com.example.Main'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.apache.commons:commons-lang3:3.13.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
Tasks
Gradle builds are composed of tasks:
tasks.register("hello") {
doLast {
println("Hello, Gradle!")
}
}
tasks.register("greet") {
dependsOn("hello")
doLast {
println("Welcome to the build!")
}
}
Built-in Tasks
| Task | Description |
|---|---|
compileJava |
Compile Java sources |
processResources |
Copy resources |
classes |
Compile + process |
test |
Run unit tests |
jar |
Build JAR |
javadoc |
Generate documentation |
clean |
Delete build directory |
Customizing Tasks
tasks.jar {
manifest {
attributes["Main-Class"] = "com.example.Main"
}
}
tasks.compileJava {
options.encoding = "UTF-8"
options.compilerArgs.add("-Xlint:all")
}
Dependency Management
Configurations
dependencies {
implementation("com.google.guava:guava:32.1.3-jre")
compileOnly("jakarta.servlet:jakarta.servlet-api:6.0.0")
runtimeOnly("ch.qos.logback:logback-classic:1.4.11")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
| Configuration | Scope |
|---|---|
implementation |
Available to this module and for compilation; not exposed transitively |
api |
Available both for compilation and exposed to consumers |
compileOnly |
Needed only for compilation, not packaged |
runtimeOnly |
Needed at runtime, not for compilation |
testImplementation |
Test dependencies |
testRuntimeOnly |
Test runtime dependencies |
Multi-Module Projects
// settings.gradle.kts
rootProject.name = "my-project"
include("core", "api", "app")
// core/build.gradle.kts
dependencies {
implementation("org.apache.commons:commons-lang3:3.13.0")
}
// app/build.gradle.kts
dependencies {
implementation(project(":core"))
}
The Gradle Wrapper
The Wrapper ensures everyone uses the same Gradle version:
gradle wrapper --gradle-version 8.5
This creates:
gradlew(Shell Script)gradlew.bat(Windows batch)gradle/wrapper/gradle-wrapper.propertiesgradle/wrapper/gradle-wrapper.jar
# Instead of `gradle build`, use:
./gradlew build
The wrapper downloads the specified Gradle version if not already present. Commit all wrapper files to version control.
Build Phases
Gradle has three phases:
- Initialization — determines which projects participate
- Configuration — evaluates build scripts, creates task graph
- Execution — runs tasks in order
// Configuration phase — runs even for `gradle clean`
println("Configuring project: ${project.name}")
tasks.register("delayed") {
doLast {
// Execution phase — only runs if this task is executed
println("This runs during execution")
}
}
Common Mistakes
- Using
compileinstead ofimplementation.compileis deprecated since Gradle 3.4. Useimplementationto reduce transitive dependency exposure. - Committing wrapper JAR but not
.gitattributes. The JAR is a binary file; configure Git LFS or ensure it is committed properly. - Putting logic in the configuration phase. Heavy computation in configuration runs even if you run
gradle clean. UsedoFirst/doLastfor execution-phase logic. - Forgetting to add
mavenCentral()Repository. Gradle has no default repository — you must declare at least one. - Not using the wrapper for CI. CI servers should use
./gradlew, not a system-installed Gradle.
Practice Questions
1. What is the difference between implementation and api dependency configurations?
implementation is not exposed transitively — consumers of your module cannot access it at compile time. api exposes the dependency to consumers.
2. Why should you use the Gradle wrapper?
It ensures reproducible builds by fixing the Gradle version. No manual installation is needed — the wrapper downloads the correct version.
3. What are the three phases of a Gradle build?
Initialization, configuration, execution.
4. How do you run a single test class in Gradle?
./gradlew test --tests "com.example.UserServiceTest"
5. What does ./gradlew build do?
It compiles, runs tests, and creates the distribution artifact (JAR, WAR, etc.).
Challenge Question:
Convert a Maven pom.xml multi-module project to Gradle Kotlin DSL. Create the settings.gradle.kts with all modules, configure allprojects with a common repository and Java version, and set up module-specific dependencies. Run ./gradlew build and verify the output.
FAQ
Mini Project
Create a complete Gradle project:
- Create
build.gradle.ktswith thejavaandapplicationplugins - Set up
mavenCentral()repository - Add JUnit 5 and Apache Commons Lang3 dependencies
- Create a
Mainclass that reverses a string usingStringUtils.reverse() - Create a test class with JUnit 5 assertions
- Generate the Gradle wrapper:
gradle wrapper --gradle-version 8.5 - Build and run:
./gradlew build && ./gradlew run - View the dependency tree:
./gradlew dependencies
What's Next
Build tools handle compilation and dependency management. Testing frameworks ensure code quality. Lesson 47 covers JUnit 5 — the standard testing framework for Java, with @Test, assertions, assumptions, parameterized tests, and test lifecycle hooks.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro