Gradle Introduction and build.gradle

3 minute read

Gradle is a modern build tool that uses Groovy or Kotlin instead of XML. It’s faster than Maven (incremental builds, build cache) and more flexible, though with a steeper learning curve.


Gradle Wrapper

Every Gradle project should include the wrapper — a script that downloads and uses the correct Gradle version:

my-project/
├── gradlew            ← Unix wrapper script
├── gradlew.bat        ← Windows wrapper script
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── build.gradle       ← Build configuration
└── settings.gradle    ← Project settings
# Always use the wrapper — NOT system Gradle
./gradlew build        # ✅
gradle build           # ❌ uses system version — might be different

Generate a wrapper:

gradle wrapper --gradle-version 8.8

Project Structure

Gradle uses the same directory layout as Maven:

src/
├── main/
│   ├── java/
│   └── resources/
└── test/
    ├── java/
    └── resources/

settings.gradle

rootProject.name = 'my-project'

// Multi-module:
// include 'api', 'service', 'common'

build.gradle (Groovy DSL)

plugins {
    id 'java'
    id 'application'
}

group = 'com.myapp'
version = '1.0.0'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.google.guava:guava:33.2.1-jre'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.3'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

application {
    mainClass = 'com.myapp.App'
}

tasks.named('test') {
    useJUnitPlatform()
}

build.gradle.kts (Kotlin DSL)

plugins {
    java
    application
}

group = "com.myapp"
version = "1.0.0"

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(21))
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.google.guava:guava:33.2.1-jre")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.3")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

application {
    mainClass.set("com.myapp.App")
}

tasks.test {
    useJUnitPlatform()
}

Groovy vs Kotlin DSL

Feature Groovy (.gradle) Kotlin (.gradle.kts)
IDE autocomplete Limited ✅ Full
Type safety ❌ Dynamic ✅ Static
Syntax Shorter Slightly verbose
Adoption Legacy projects New projects

Recommendation: Use Kotlin DSL for new projects — better IDE support and type safety.


Running Builds

# Build (compile + test + jar)
./gradlew build

# Just compile
./gradlew compileJava

# Run tests
./gradlew test

# Run application
./gradlew run

# Clean build output
./gradlew clean

# Clean + build
./gradlew clean build

# List all available tasks
./gradlew tasks

Terminal Output

$ ./gradlew build

> Task :compileJava
> Task :processResources
> Task :classes
> Task :jar
> Task :compileTestJava
> Task :processTestResources
> Task :testClasses
> Task :test
> Task :check
> Task :build

BUILD SUCCESSFUL in 4s
7 actionable tasks: 7 executed

Repositories

repositories {
    mavenCentral()             // Default — most libraries
    mavenLocal()               // ~/.m2/repository
    google()                   // Android libraries
    maven {                    // Private repo
        url 'https://nexus.mycompany.com/repository/maven-releases/'
        credentials {
            username = project.findProperty("nexusUser") ?: ""
            password = project.findProperty("nexusPass") ?: ""
        }
    }
}

Gradle Daemon

Gradle runs a background daemon process to speed up builds:

# Check daemon status
./gradlew --status

# Stop daemon
./gradlew --stop

# Run without daemon (CI/CD)
./gradlew build --no-daemon
Feature With Daemon Without Daemon
First build ~10s ~10s
Subsequent builds ~2s ~10s

Build Output

build/
├── classes/java/main/          ← Compiled classes
├── classes/java/test/          ← Compiled test classes
├── libs/                       ← JAR files
│   └── my-project-1.0.0.jar
├── reports/tests/test/         ← HTML test report
├── test-results/               ← XML test results
└── tmp/                        ← Temporary files

Gradle uses build/ (not target/ like Maven).


Gradle Init — Create New Project

gradle init --type java-application --dsl kotlin

Interactive prompts:

Project name: my-project
Source package: com.myapp
Java version: 21
Build script DSL: Kotlin
Test framework: JUnit Jupiter

Common Mistakes

Mistake Fix
Using gradle instead of ./gradlew Always use the wrapper
Missing useJUnitPlatform() JUnit 5 tests won’t run without it
Committing .gradle/ directory Add .gradle/ to .gitignore
Confusing build/ with target/ Gradle uses build/, Maven uses target/

Key Takeaways

  1. Always use ./gradlew (wrapper) — ensures consistent Gradle version.
  2. build.gradle (Groovy) or build.gradle.kts (Kotlin) — prefer Kotlin for new projects.
  3. Gradle uses the same directory layout as Maven.
  4. The daemon makes subsequent builds fast.
  5. Output goes to build/ (not target/).

What’s Next?

Next: Gradle Tasks, Dependencies, and Plugins — custom tasks, dependency configurations, version catalogs, and the Spring Boot plugin.

Updated: