$npx -y skills add hanamizuki/solopreneur --skill gradle-build-performanceDebug and optimize Android/Gradle build performance. Use when builds are slow, investigating CI/CD performance, analyzing build scans, or identifying compilation bottlenecks.
| 1 | # Gradle Build Performance |
| 2 | |
| 3 | ## When to Use |
| 4 | |
| 5 | - Build times are slow (clean or incremental) |
| 6 | - Investigating build performance regressions |
| 7 | - Analyzing Gradle Build Scans |
| 8 | - Identifying configuration vs execution bottlenecks |
| 9 | - Optimizing CI/CD build times |
| 10 | - Enabling Gradle Configuration Cache |
| 11 | - Reducing unnecessary recompilation |
| 12 | - Debugging kapt/KSP annotation processing |
| 13 | |
| 14 | ## Example Prompts |
| 15 | |
| 16 | - "My builds are slow, how can I speed them up?" |
| 17 | - "How do I analyze a Gradle build scan?" |
| 18 | - "Why is configuration taking so long?" |
| 19 | - "Why does my project always recompile everything?" |
| 20 | - "How do I enable configuration cache?" |
| 21 | - "Why is kapt so slow?" |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## Workflow |
| 26 | |
| 27 | 1. **Measure Baseline** — Clean build + incremental build times |
| 28 | 2. **Generate Build Scan** — `./gradlew assembleDebug --scan` |
| 29 | 3. **Identify Phase** — Configuration? Execution? Dependency resolution? |
| 30 | 4. **Apply ONE optimization** — Don't batch changes |
| 31 | 5. **Measure Improvement** — Compare against baseline |
| 32 | 6. **Verify in Build Scan** — Visual confirmation |
| 33 | |
| 34 | --- |
| 35 | |
| 36 | ## Quick Diagnostics |
| 37 | |
| 38 | ### Generate Build Scan |
| 39 | |
| 40 | ```bash |
| 41 | ./gradlew assembleDebug --scan |
| 42 | ``` |
| 43 | |
| 44 | ### Profile Build Locally |
| 45 | |
| 46 | ```bash |
| 47 | ./gradlew assembleDebug --profile |
| 48 | # Opens report in build/reports/profile/ |
| 49 | ``` |
| 50 | |
| 51 | ### Build Timing Summary |
| 52 | |
| 53 | ```bash |
| 54 | ./gradlew assembleDebug --info | grep -E "^\:.*" |
| 55 | # Or view in Android Studio: Build > Analyze APK Build |
| 56 | ``` |
| 57 | |
| 58 | --- |
| 59 | |
| 60 | ## Build Phases |
| 61 | |
| 62 | | Phase | What Happens | Common Issues | |
| 63 | |-------|--------------|---------------| |
| 64 | | **Initialization** | `settings.gradle.kts` evaluated | Too many `include()` statements | |
| 65 | | **Configuration** | All `build.gradle.kts` files evaluated | Expensive plugins, eager task creation | |
| 66 | | **Execution** | Tasks run based on inputs/outputs | Cache misses, non-incremental tasks | |
| 67 | |
| 68 | ### Identify the Bottleneck |
| 69 | |
| 70 | ``` |
| 71 | Build scan → Performance → Build timeline |
| 72 | ``` |
| 73 | |
| 74 | - **Long configuration phase**: Focus on plugin and buildscript optimization |
| 75 | - **Long execution phase**: Focus on task caching and parallelization |
| 76 | - **Dependency resolution slow**: Focus on repository configuration |
| 77 | |
| 78 | --- |
| 79 | |
| 80 | ## 12 Optimization Patterns |
| 81 | |
| 82 | ### 1. Enable Configuration Cache |
| 83 | |
| 84 | Caches configuration phase across builds (AGP 8.0+): |
| 85 | |
| 86 | ```properties |
| 87 | # gradle.properties |
| 88 | org.gradle.configuration-cache=true |
| 89 | org.gradle.configuration-cache.problems=warn |
| 90 | ``` |
| 91 | |
| 92 | ### 2. Enable Build Cache |
| 93 | |
| 94 | Reuses task outputs across builds and machines: |
| 95 | |
| 96 | ```properties |
| 97 | # gradle.properties |
| 98 | org.gradle.caching=true |
| 99 | ``` |
| 100 | |
| 101 | ### 3. Enable Parallel Execution |
| 102 | |
| 103 | Build independent modules simultaneously: |
| 104 | |
| 105 | ```properties |
| 106 | # gradle.properties |
| 107 | org.gradle.parallel=true |
| 108 | ``` |
| 109 | |
| 110 | ### 4. Increase JVM Heap |
| 111 | |
| 112 | Allocate more memory for large projects: |
| 113 | |
| 114 | ```properties |
| 115 | # gradle.properties |
| 116 | org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC |
| 117 | ``` |
| 118 | |
| 119 | ### 5. Use Non-Transitive R Classes |
| 120 | |
| 121 | Reduces R class size and compilation (AGP 8.0+ default): |
| 122 | |
| 123 | ```properties |
| 124 | # gradle.properties |
| 125 | android.nonTransitiveRClass=true |
| 126 | ``` |
| 127 | |
| 128 | ### 6. Migrate kapt to KSP |
| 129 | |
| 130 | KSP is 2x faster than kapt for Kotlin: |
| 131 | |
| 132 | ```kotlin |
| 133 | // Before (slow) |
| 134 | kapt("com.google.dagger:hilt-compiler:2.51.1") |
| 135 | |
| 136 | // After (fast) |
| 137 | ksp("com.google.dagger:hilt-compiler:2.51.1") |
| 138 | ``` |
| 139 | |
| 140 | ### 7. Avoid Dynamic Dependencies |
| 141 | |
| 142 | Pin dependency versions: |
| 143 | |
| 144 | ```kotlin |
| 145 | // BAD: Forces resolution every build |
| 146 | implementation("com.example:lib:+") |
| 147 | implementation("com.example:lib:1.0.+") |
| 148 | |
| 149 | // GOOD: Fixed version |
| 150 | implementation("com.example:lib:1.2.3") |
| 151 | ``` |
| 152 | |
| 153 | ### 8. Optimize Repository Order |
| 154 | |
| 155 | Put most-used repositories first: |
| 156 | |
| 157 | ```kotlin |
| 158 | // settings.gradle.kts |
| 159 | dependencyResolutionManagement { |
| 160 | repositories { |
| 161 | google() // First: Android dependencies |
| 162 | mavenCentral() // Second: Most libraries |
| 163 | // Third-party repos last |
| 164 | } |
| 165 | } |
| 166 | ``` |
| 167 | |
| 168 | ### 9. Use includeBuild for Local Modules |
| 169 | |
| 170 | Composite builds are faster than `project()` for large monorepos: |
| 171 | |
| 172 | ```kotlin |
| 173 | // settings.gradle.kts |
| 174 | includeBuild("shared-library") { |
| 175 | dependencySubstitution { |
| 176 | substitute(module("com.example:shared")).using(project(":")) |
| 177 | } |
| 178 | } |
| 179 | ``` |
| 180 | |
| 181 | ### 10. Enable Incremental Annotation Processing |
| 182 | |
| 183 | ```properties |
| 184 | # gradle.properties |
| 185 | kapt.incremental.apt=true |
| 186 | kapt.use.worker.api=true |
| 187 | ``` |
| 188 | |
| 189 | ### 11. Avoid Configuration-Time I/O |
| 190 | |
| 191 | Don't read files or make network calls during configuration: |
| 192 | |
| 193 | ```kotlin |
| 194 | // BAD: Runs during configuration |
| 195 | val version = file("version.txt").readText() |
| 196 | |
| 197 | // GOOD: Defer to execution |
| 198 | val version = providers.fileContents(file("version.txt")).asText |
| 199 | ``` |
| 200 | |
| 201 | ### 12. Use Lazy Task Configuration |
| 202 | |
| 203 | Avoid `create()`, use `register()`: |
| 204 | |
| 205 | ```kotlin |
| 206 | // BAD: Eagerly configured |
| 207 | tasks.create("myTask") { ... } |
| 208 | |
| 209 | // GOOD: Lazily configured |
| 210 | tasks.register("myTask") { ... } |
| 211 | ``` |
| 212 | |
| 213 | --- |
| 214 | |
| 215 | ## Common Bottleneck Analysis |
| 216 | |
| 217 | ### Slow Configuration Phase |
| 218 | |
| 219 | **Symptoms**: Build scan shows long "Configuring build" time |
| 220 | |
| 221 | **Causes & Fixes**: |
| 222 | | Cause | Fix | |
| 223 | |-------|-----| |
| 224 | | |