Irbisa · Cheatsheet
Gradle & Modularization
Gradle KTS, version catalogs, convention plugins, KSP, build variants, configuration cache, modules
Which Gradle files make up an Android project, and what does each one do?
// settings.gradle.ktspluginManagement { repositories { google() mavenCentral() gradlePluginPortal()…What is Android Lint, and how do you make it fail the build instead of producing a report nobody reads?
// app/build.gradle.ktsandroid { lint { abortOnError = true // the default: errors fail the task warningsAsErrors = true baseline = file("lint-baseline.xml") // report only issues newer than this file…What is multidex, why did it exist, and do you still need it?
What does
./gradlew helloprint for this build script, and what does./gradlew helpprint?// build.gradle.ktsprintln("1: script body") tasks.register("hello") { println("2: configuring hello") doLast { println("3: running hello") }} tasks.register("cleanup") { println("4: configuring cleanup")} println("5: end of script")What is the difference between
implementation,api,compileOnlyandruntimeOnly?// core/network/build.gradle.ktsdependencies { api(project(":core:model")) // `User` from :core:model is in this module's public API implementation(libs.retrofit) // used inside, never exposed compileOnly(libs.javax.annotation) // annotations only, not packaged runtimeOnly(libs.slf4j.android) // a backend nobody imports…What is a version catalog, and why do you still need a BOM next to it?
// gradle/libs.versions.toml// [versions]// composeBom = "2025.09.00"// retrofit = "3.0.0"//// [libraries]…What is the difference between build types and product flavors, and how do you ship a staging app with its own API URL and icon next to production?
android { namespace = "com.example.app" buildFeatures { buildConfig = true } // off by default since AGP 8 defaultConfig { applicationId = "com.example.app"…How many build variants does this configuration produce, and which source sets does
freePlayDebugcompile?android { flavorDimensions += listOf("tier", "store") productFlavors { create("free") { dimension = "tier" } create("paid") { dimension = "tier" } create("play") { dimension = "store" } create("huawei") { dimension = "store" } } buildTypes { getByName("debug") getByName("release") create("qa") { initWith(getByName("release")) } }}What happens between
./gradlew assembleReleaseand a signed APK?What is the difference between kapt and KSP, and what do you gain by migrating?
// before:// plugins { id("org.jetbrains.kotlin.kapt") }// kapt(libs.room.compiler) plugins { alias(libs.plugins.android.library)…How does Gradle resolve dependency version conflicts, and how do you track down a "Duplicate class" error?
// Who asked for it, and why did this version win?// ./gradlew :app:dependencyInsight --configuration releaseRuntimeClasspath --dependency okio dependencies { // one family, one version implementation(platform(libs.okhttp.bom))…What does a Java toolchain do in an Android build, and what does "Inconsistent JVM-target compatibility" mean?
kotlin { jvmToolchain(17) } android { compileOptions { // both must name the same level sourceCompatibility = JavaVersion.VERSION_17…Why does every edit in
buildSrcreconfigure the whole project, and what changes when convention plugins live in an included build?// settings.gradle.ktspluginManagement { includeBuild("build-logic") // a separate build, not a project dependency} // build-logic/convention/build.gradle.kts…This code generation task reruns on every build and fails once the configuration cache is on: what is wrong with it, and how do you fix it?
tasks.register("generateConfig") { doLast { val dir = project.layout.buildDirectory.dir("generated/config").get().asFile dir.mkdirs() val url = System.getenv("API_URL") ?: "https://api.example.com" File(dir, "Config.kt").writeText("package com.example\n\nconst val API_URL = \"$url\"\n") }} tasks.named("preBuild") { dependsOn("generateConfig") }What is the difference between the build cache and the configuration cache, and what stops each of them from hitting?
A Gradle build is slow: how do you find out why, and which changes usually give the biggest win?
# gradle.properties - change one thing at a time and measure againorg.gradle.caching=trueorg.gradle.configuration-cache=trueorg.gradle.parallel=trueorg.gradle.jvmargs=-Xmx6g -XX:+UseParallelGCkotlin.daemon.jvmargs=-Xmx3g…When does splitting a module into
:apiand:implspeed up the build, and when is it just ceremony?How do you make dependency resolution reproducible, so the same commit resolves the same artifacts next month?
What do you have to get right when publishing an Android library module as an AAR to a Maven repository?
// core/network/build.gradle.ktsplugins { alias(libs.plugins.android.library) `maven-publish`}…How does a dynamic feature module change the dependency graph, and how does the base app open a screen from it?
// app/build.gradle.ktsandroid { dynamicFeatures += setOf(":feature:scan")} // feature/scan/build.gradle.kts - note the direction of the dependency…