| name | gradle-expert |
| description | Expert knowledge for Gradle Build Tool, dependency management, and Gradle-to-Bazel migration. Use for build configuration and project lifecycle questions. |
| version | 1.2.0 |
| keywords | ["gradle","build","kotlin-dsl","migration","java","groovy"] |
gradle-expert
Keyword: gradle | Platforms: gemini,claude,codex
Modern Gradle Build Tool Expert Skill - Specialized in performance, dependency management, and polyglot builds.
Core Mandates
- DSL Proficiency: Expert in both Groovy DSL (
build.gradle) and Kotlin DSL (build.gradle.kts).
- Dependency Configurations: Distinguish between
api, implementation, runtimeOnly, and testImplementation.
- Build Performance: Leverage Build Cache, Daemon, and Parallel execution to optimize feedback loops.
- Convention over Configuration: Prefer built-in plugins (
java-library, application, maven-publish) over custom logic.
build.gradle.kts Examples
Quarkus Project
plugins {
java
id("io.quarkus") version "3.20.1"
}
repositories {
mavenCentral()
}
val quarkusPlatformVersion: String by project
dependencies {
implementation(enforcedPlatform("io.quarkus.platform:quarkus-bom:${quarkusPlatformVersion}"))
implementation("io.quarkus:quarkus-rest")
implementation("io.quarkus:quarkus-arc")
implementation("io.quarkus:quarkus-hibernate-orm-panache")
testImplementation("io.quarkus:quarkus-junit5")
testImplementation("io.rest-assured:rest-assured")
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
tasks.withType<Test> {
useJUnitPlatform()
systemProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager")
}
Multi-Module with Version Catalog
[versions]
quarkus = "3.20.1"
jackson = "2.18.2"
junit = "5.11.4"
assertj = "3.27.3"
[libraries]
quarkus-bom = { module = "io.quarkus.platform:quarkus-bom", version.ref = "quarkus" }
quarkus-rest = { module = "io.quarkus:quarkus-rest" }
quarkus-arc = { module = "io.quarkus:quarkus-arc" }
quarkus-hibernate = { module = "io.quarkus:quarkus-hibernate-orm-panache" }
quarkus-junit5 = { module = "io.quarkus:quarkus-junit5" }
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" }
assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" }
[plugins]
quarkus = { id = "io.quarkus", version.ref = "quarkus" }
rootProject.name = "my-platform"
include("common", "service-user", "service-order")
plugins {
java
alias(libs.plugins.quarkus) apply false
}
subprojects {
apply(plugin = "java")
repositories {
mavenCentral()
}
dependencies {
implementation(platform(libs.quarkus.bom))
implementation(platform(libs.junit.bom))
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
}
plugins {
alias(libs.plugins.quarkus)
}
dependencies {
implementation(project(":common"))
implementation(libs.quarkus.rest)
implementation(libs.quarkus.arc)
implementation(libs.quarkus.hibernate)
testImplementation(libs.quarkus.junit5)
testImplementation(libs.assertj)
}
Dependency Configuration Decision Tree
Does the consuming module need this at compile time?
YES → Does the consuming module also see this in ITS public API?
YES → api (leaks to consumers' compile classpath)
NO → implementation (hidden from consumers)
NO → Is it needed at runtime only?
YES → runtimeOnly (e.g., JDBC drivers, SLF4J bindings)
NO → Is it only for tests?
YES → testImplementation
NO → compileOnly (e.g., annotation processors, provided-like)
Do vs Don't
dependencies {
api("com.google.guava:guava:33.4.0-jre")
api("io.quarkus:quarkus-hibernate-orm-panache")
}
dependencies {
api("com.example:shared-dto:1.0")
implementation("com.google.guava:guava:33.4.0-jre")
implementation("io.quarkus:quarkus-hibernate-orm-panache")
}
Version Conflict Resolution Workflow
Step 1: Identify the conflict
./gradlew dependencies --configuration runtimeClasspath
./gradlew dependencyInsight --dependency jackson-databind --configuration runtimeClasspath
Step 2: Understand Gradle's resolution strategy
Gradle uses highest version wins by default. This is usually safe but can break binary compatibility.
Step 3: Resolve
configurations.all {
resolutionStrategy {
force("com.fasterxml.jackson.core:jackson-databind:2.18.2")
}
}
dependencies {
implementation(platform("com.fasterxml.jackson:jackson-bom:2.18.2"))
}
dependencies {
implementation("some-lib:some-lib:1.0") {
exclude(group = "com.fasterxml.jackson.core", module = "jackson-databind")
}
}
configurations.all {
resolutionStrategy {
failOnVersionConflict()
}
}
Resolution Priority
| Priority | Strategy | When to use |
|---|
| 1st | BOM / platform() | When a BOM exists (jackson-bom, netty-bom, quarkus-bom) |
| 2nd | Version Catalog | Centralize versions in libs.versions.toml |
| 3rd | exclude() | When one lib brings a known bad transitive |
| 4th | force() | Last resort - overrides everything, can mask issues |
Common Errors & Fixes
"Could not resolve all dependencies"
repositories {
mavenCentral()
maven {
url = uri("https://nexus.example.com/repository/maven-releases/")
credentials {
username = providers.environmentVariable("MAVEN_USER").orNull
password = providers.environmentVariable("MAVEN_TOKEN").orNull
}
}
}
"Execution failed: A valid toolchain could not be found"
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
Build cache not working
# gradle.properties
org.gradle.caching=true
org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError
buildCache {
local {
isEnabled = true
}
remote<HttpBuildCache> {
url = uri("https://cache.example.com/cache/")
isPush = System.getenv("CI") != null
}
}
"Cannot change dependencies after configuration resolution"
val runtimeJars = configurations.runtimeClasspath.get().files
tasks.register("listDeps") {
val runtimeCp = configurations.runtimeClasspath
doLast {
runtimeCp.get().files.forEach { println(it) }
}
}
Slow builds diagnostic
./gradlew build --scan
./gradlew build --profile
./gradlew build --configuration-cache
Slow builds optimization checklist
| Check | Action |
|---|
| Daemon enabled? | org.gradle.daemon=true in gradle.properties |
| Parallel builds? | org.gradle.parallel=true |
| Build cache? | org.gradle.caching=true |
| Configuration cache? | --configuration-cache (Gradle 8.1+) |
Unnecessary api deps? | Switch to implementation to reduce recompilation |
allprojects{} / subprojects{} blocks? | Migrate to convention plugins |
| Task Configuration Avoidance? | Use tasks.register not tasks.create |
Gradle-to-Bazel Migration
Configuration Mapping Table
| Gradle | Bazel | Notes |
|---|
api | exports = [...] | Visible to transitive consumers |
implementation | deps = [...] | Hidden from consumers |
runtimeOnly | runtime_deps = [...] | Not on compile classpath |
compileOnly | deps = [...] + neverlink = True | Compile but not package |
testImplementation | test target deps | Separate test target |
project(":sub") | "//sub:target" | Bazel label |
./gradlew build | bazel build //... | Build all |
./gradlew test | bazel test //... | Test all |
| Version Catalog | rules_jvm_external | Different mechanism |
Exporting Dependencies for Bazel
./gradlew dependencies --configuration runtimeClasspath \
| grep '\\---' | sed 's/.*--- //' | sort -u
Advanced Patterns
- Build Scan: Using Gradle Build Scans for debugging performance and dependency issues.
- Custom Tasks: Writing idiomatic tasks using the Task Configuration Avoidance API.
- Version Catalogs: Managing versions and libraries centrally via
libs.versions.toml.
Expert Tips
- Avoid using the deprecated
compile configuration; use implementation or api.
- Use
./gradlew dependencies --configuration runtimeClasspath to visualize the dependency graph.
- Prefer Kotlin DSL for better IDE support and type safety in complex builds.
- Use
gradle wrapper --gradle-version=8.12 to pin Gradle version for reproducibility.
- Always use
tasks.register (lazy) over tasks.create (eager) for Task Configuration Avoidance.
- Use
./gradlew build --dry-run to preview task execution order without running anything.
🌐 Gradle Knowledge Sources
Directive: Use web_fetch to find Kotlin DSL syntax, version catalog patterns, or Gradle-to-Bazel migration strategies if a build configuration is complex.
References
Skill Interoperability
The gradle-expert 🐘 skill provides expertise in modern build DSLs and performance, supporting:
- rules-quarkus 🔧: Facilitates the migration of Gradle-based projects to Bazel.