build.gradle Example
Gradle uses build.gradle as the central configuration file for a project. Written in the Groovy DSL, it defines plugins, dependencies, repositories, project metadata, and custom build logic. A typical Java, Android, or Spring Boot project can be configured with a relatively small script, while larger projects can use the same file to coordinate compilation, testing, packaging, and deployment tasks.
Kotlin DSL equivalents are usually stored in
build.gradle.kts, but the configuration model remains largely the same.
The following example configures a standard Java application:
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.guava:guava:32.1.3-jre'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
application {
mainClass = 'com.example.Main'
}
Each section has a clear purpose:
pluginsapplies plugins to the project. Thejavaplugin enables Java compilation, testing, and JAR packaging, whileapplicationadds a runnable application task.groupandversionidentify the project and its published artifact.repositoriesdeclares where Gradle should look for dependencies.mavenCentral()points to Maven Central.dependencieslists external libraries and test tools.applicationidentifies the entry-point class used by tasks such asrun.
After applying the application plugin, the application can be started with:
./gradlew run
Using the Gradle Wrapper is preferable to a system-wide Gradle installation because it keeps the build tool version consistent across developers and CI environments.
Understanding Dependency Configurations
Gradle’s dependency configurations determine which parts of a project can access a library. Choosing the correct configuration prevents unnecessary dependencies from leaking into downstream projects.
plugins {
id 'java'
id 'java-library'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.0'
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
runtimeOnly 'com.mysql:mysql-connector-j:8.2.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
The most common configurations are:
implementationmakes a dependency available during compilation and runtime, but does not expose it on the consumer’s compile classpath. This is the usual choice for application dependencies.apiexposes a dependency to projects that consume the current library. It requires thejava-libraryplugin and should be reserved for types that appear in a library’s public API.compileOnlyprovides a dependency during compilation without including it in the runtime artifact. It is commonly used for Lombok, though annotation processing must also be enabled as shown above.annotationProcessorsupplies annotation processors used at compile time.runtimeOnlyincludes a dependency only when the application runs. Database drivers are a typical example.testImplementationmakes a library available to test source sets without adding it to the main application.
Keeping production and test dependencies separate reduces build size and avoids accidental use of test-only libraries in production code.
Spring Boot Configuration
Spring Boot projects usually combine the Spring Boot plugin with the dependency-management plugin:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '1.0.0'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
The Spring Boot dependency-management plugin imports a dependency bill of materials supplied by the selected Spring Boot release. As a result, compatible versions of related libraries are selected automatically, and individual version numbers can usually be omitted.
The Java toolchain configuration tells Gradle to compile with Java 17. Toolchains are more precise than setting sourceCompatibility alone because they allow Gradle to locate or provision the required JDK.
For a Spring Boot application, the usual local startup command is:
./gradlew bootRun
Adding Custom Tasks
Build files can also extend Gradle with project-specific tasks. For example, the following task prints basic project information:
tasks.register('printInfo') {
group = 'help'
description = 'Prints the project name and version.'
doLast {
println "Project: ${project.name}, Version: ${project.version}"
}
}
Run it with:
./gradlew printInfo
The group and description properties make the task easier to discover through ./gradlew tasks.
Existing tasks can also be customized:
tasks.named('build') {
doLast {
println 'Build completed successfully.'
}
}
This example adds an action to the end of the standard build lifecycle. For production scripts, custom tasks should declare their inputs and outputs so that Gradle can cache them, skip unnecessary execution, and participate correctly in incremental builds.
Essential Gradle Commands
These commands cover most day-to-day development tasks:
./gradlew buildcompiles the project, runs tests, and creates the distributable artifact../gradlew cleanremoves files generated by previous builds../gradlew testruns the test suite../gradlew runstarts an application configured with theapplicationplugin../gradlew bootRunstarts a Spring Boot application../gradlew dependenciesdisplays the dependency tree and helps identify conflicting or unexpected versions../gradlew taskslists available tasks../gradlew projectsshows the structure of a multi-project build.
When diagnosing dependency problems, the more focused report is often more useful:
./gradlew dependencyInsight \
--dependency guava \
--configuration runtimeClasspath
This command shows which dependency introduced a particular library and which versions were selected.
Practical Recommendations
Generate and commit the Wrapper. Run
gradle wrapperonce, then commitgradlew,gradlew.bat, and the files undergradle/wrapper. Team members and CI servers can then use the same Gradle version.Use modern dependency configurations. Replace legacy configurations such as
compileandtestCompilewithimplementation,api, andtestImplementation.Centralize versions in larger builds. Multi-project projects can use a version catalog in
gradle/libs.versions.toml, shared convention plugins, or root-project configuration to avoid duplicated version numbers.Keep secrets out of the build script. Do not hardcode repository credentials, API tokens, or passwords. Use environment variables, an encrypted secrets manager, or carefully protected properties in
gradle.properties.Avoid unnecessary configuration. Prefer lazy task registration with
tasks.register, use task inputs and outputs for cacheable work, and avoid broad actions that force Gradle to rebuild unchanged files.Review dependency changes. Run the dependency report before upgrading a major library, and check whether new transitive dependencies introduce security risks or conflicts.
With these fundamentals in place, build.gradle becomes more than a list of dependencies: it becomes a reproducible and extensible definition of how the project is compiled, tested, packaged, and delivered.