gradle-expert
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, andtestImplementation. - 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
// build.gradle.kts
plugins {
java
id("io.quarkus") version "3.20.1"
}
repositories {
mavenCentral()
}
val quarkusPlatformVersion: String by project // from gradle.properties
dependencies {
// BOM - manages all Quarkus versions
implementation(enforcedPlatform("io.quarkus.platform:quarkus-bom:${quarkusPlatformVersion}"))
// No versions needed - managed by BOM
implementation("io.quarkus:quarkus-rest")
implementation("io.quarkus:quarkus-arc")
implementation("io.quarkus:quarkus-hibernate-orm-panache")
// Test
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
# gradle/libs.versions.toml
[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" }
// settings.gradle.kts
rootProject.name = "my-platform"
include("common", "service-user", "service-order")
// build.gradle.kts (root)
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))
}
}
}
// service-user/build.gradle.kts
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
// BAD - using 'api' everywhere leaks dependencies, slows compilation
dependencies {
api("com.google.guava:guava:33.4.0-jre") // Leaked!
api("io.quarkus:quarkus-hibernate-orm-panache") // Leaked!
}
// GOOD - only 'api' what consumers actually need in their code
dependencies {
api("com.example:shared-dto:1.0") // Consumers use these types
implementation("com.google.guava:guava:33.4.0-jre") // Internal only
implementation("io.quarkus:quarkus-hibernate-orm-panache")
}
Version Conflict Resolution Workflow
Step 1: Identify the conflict
# Show dependency tree for a specific configuration
./gradlew dependencies --configuration runtimeClasspath
# Filter for a specific module
./gradlew dependencyInsight --dependency jackson-databind --configuration runtimeClasspath
# Output:
# com.fasterxml.jackson.core:jackson-databind:2.18.2
# variant "compile" [
# Requested: 2.14.0 ← conflict
# Selected: 2.18.2 ← Gradle picked highest
# ]
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
// Option A: Force a specific version (use sparingly)
configurations.all {
resolutionStrategy {
force("com.fasterxml.jackson.core:jackson-databind:2.18.2")
}
}
// Option B: Use a BOM/platform (preferred)
dependencies {
implementation(platform("com.fasterxml.jackson:jackson-bom:2.18.2"))
// All Jackson modules now use 2.18.2
}
// Option C: Exclude transitive dependency
dependencies {
implementation("some-lib:some-lib:1.0") {
exclude(group = "com.fasterxml.jackson.core", module = "jackson-databind")
}
}
// Option D: Fail on conflict (strict mode for CI)
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"
// Cause: Missing repository or wrong coordinates
repositories {
mavenCentral()
// Add private repo if needed:
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"
// Fix: Specify Java toolchain
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
// Or in gradle.properties:
// org.gradle.java.home=/path/to/jdk21
Build cache not working
# gradle.properties
org.gradle.caching=true
org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError
// settings.gradle.kts - remote cache
buildCache {
local {
isEnabled = true
}
remote<HttpBuildCache> {
url = uri("https://cache.example.com/cache/")
isPush = System.getenv("CI") != null // Only push from CI
}
}
"Cannot change dependencies after configuration resolution"
// BAD - resolving a configuration during configuration phase
val runtimeJars = configurations.runtimeClasspath.get().files // Triggers resolution!
// GOOD - defer to execution phase
tasks.register("listDeps") {
val runtimeCp = configurations.runtimeClasspath
doLast {
runtimeCp.get().files.forEach { println(it) }
}
}
Slow builds diagnostic
# Generate build scan (interactive report)
./gradlew build --scan
# Profile locally
./gradlew build --profile
# Opens report in build/reports/profile/
# Check configuration cache compatibility
./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
# Generate dependency list from Gradle
./gradlew dependencies --configuration runtimeClasspath \
| grep '\\---' | sed 's/.*--- //' | sort -u
# Then translate to rules_jvm_external format in MODULE.bazel
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
compileconfiguration; useimplementationorapi. - Use
./gradlew dependencies --configuration runtimeClasspathto visualize the dependency graph. - Prefer Kotlin DSL for better IDE support and type safety in complex builds.
- Use
gradle wrapper --gradle-version=8.12to pin Gradle version for reproducibility. - Always use
tasks.register(lazy) overtasks.create(eager) for Task Configuration Avoidance. - Use
./gradlew build --dry-runto preview task execution order without running anything.
🌐 Gradle Knowledge Sources
Directive: Use
web_fetchto find Kotlin DSL syntax, version catalog patterns, or Gradle-to-Bazel migration strategies if a build configuration is complex.
- Gradle Kotlin DSL Primer: Kotlin DSL Guide - Type-safe build scripts.
- Dependency Management: Managing Dependencies - Configurations, platforms, and catalogs.
- Gradle-to-Bazel Migration: Migrating from Gradle to Bazel - Step-by-step transition.
- Build Performance: Optimizing Gradle Builds - Cache, daemon, and parallel execution.
- Quarkus Gradle Tooling: Quarkus Gradle Guide - Plugin configuration.
References
- Gradle Official User Guide
- rules_jvm_external Documentation
- Gradle Version Catalogs
- Quarkus Documentation
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.
More from kinhluan/rules-quarkus-skills
quarkus-expert
High-performance Quarkus framework expertise covering reactive patterns, CDI, build-time augmentation, and cloud-native development. Use for general Quarkus questions.
19vertx-expert
Expert knowledge for Eclipse Vert.x, the reactive engine behind Quarkus. Use for deep reactive programming, Event Loop, and non-blocking I/O questions.
13bazel-expert
Expert knowledge for writing idiomatic Bazel rules, Starlark best practices, and build performance optimization. Use for Bazel build system questions.
9maven-expert
Expert knowledge for Apache Maven, dependency management, BOMs, and Maven-to-Bazel migration. Use for build configuration and project lifecycle questions.
9rules-quarkus
Expert knowledge for building Quarkus applications with Bazel using the rules_quarkus build system. Use when user asks about Quarkus+Bazel builds, augmentation, or troubleshooting.
8java-expert
Expert knowledge for Modern Java (21+) development, including Virtual Threads, performance tuning, and idiomatic clean code. Use for deep Java language/logic questions.
8