Does the build cache work with Kotlin and Android builds?
Yes, for a small Kotlin/JVM project and a small Android project. In a repeat build, Gradle took the Kotlin compile tasks, the Java compile and the dex tasks from FosterStack Cache, a server you run yourself, instead of running them again.
The short answer for Kotlin
- Kotlin compiles came from the cache. In a repeat build,
compileKotlinandcompileTestKotlinwere restored, and so werecompileJavafor the Java file in the same module and thetesttask. - The jar tasks ran every time. They were not restored in any of our builds.
- After a change inside a method, only that module's Kotlin compile ran again. The app module, which uses core, still restored its Kotlin compile, but its test ran again.
- After a new public function, the Kotlin compile ran again in both modules. The Java compile in the changed module ran too, and so did the test.
The short answer for Android
- A repeat build restored 35 of 78 tasks. That included the Kotlin compile of both modules, the Java compile of the library, dexing, and most resource and manifest tasks.
- 31 of the 78 tasks still ran in the repeat build. They include packaging the APK, bundling the library and merging assets, which ran in every build.
- After a change inside a method in the library, its Kotlin compile ran again, and so did a dex merge task and two small library tasks. That left 31 of 78 restored. The app's own Kotlin compile was still restored.
- After a new public function in the library, the library's Kotlin and Java compiles ran again, and so did the app's Kotlin compile. 29 tasks were restored.
What to do
Our advice, not a test result:
- Look for FROM-CACHE on the compile and test lines. That is where a Kotlin build shows its hits. See how to measure your hit rate.
- Do not count the jar and APK packaging tasks as misses. They ran in every build, and 31 Android tasks ran even in a repeat build.
- Keep the Kotlin plugin version and the Java version the same on laptops and CI, so entries should be shared. If the hit rate is low, see why the Gradle hit rate is low.
How we checked
We built a small Kotlin project twice in each of three cases, always on a new empty FosterStack Cache server. Build 1 stored the results. Build 2 used a fresh copy of the project. This table shows build 2.
| Task | Nothing changed | Body change in core | New public function in core |
|---|---|---|---|
:core:compileKotlin | from cache | ran | ran |
:core:compileJava | from cache | from cache | ran |
:app:compileKotlin | from cache | from cache | ran |
:app:compileTestKotlin | from cache | from cache | ran |
:app:test | from cache | ran | ran |
:core:jar and :app:jar | ran | ran | ran |
What: Gradle 9.8.0, the Kotlin Gradle plugin 2.4.21, Temurin 21.0.12.1, FosterStack Cache 0.2.1, on a Mac (arm64). Two modules: core has a Kotlin class and one Java file, app has a Kotlin class and one test and uses core. The command was gradle build.
How: every build used a fresh copy of the project and Gradle's local cache was off. One Gradle home was shared for downloads (the plugin and the test libraries), and it was filled first by a build with the cache off. Tasks with nothing to compile or test are left out. Each case was one run.
Android, on a GitHub-hosted machine. We ran three cases on a small Android project, two builds each. Each case used a new empty cache server. Build 1 stored the results, and build 2 used a fresh copy of the project. This table shows build 2.
| Case | Tasks restored (of 78) | Library Kotlin compile | App Kotlin compile |
|---|---|---|---|
| Nothing changed | 35 | from cache | from cache |
| Body change in the library | 31 | ran | from cache |
| New public function in the library | 29 | ran | ran |
Android run: a GitHub-hosted machine, Ubuntu 24 image 20261004.327.1, 4 vCPUs (AMD EPYC 7763), 16 GB. The run and its log are public, with every task listed, and the script is bin/bench-android.sh.
What: the Android Gradle plugin 9.4.1, which brings Kotlin support with it, and the Android SDK already on the machine (compile SDK 36, build tools 37.0.0). Gradle 9.8.0, Java 21.0.12.1, FosterStack Cache 0.2.1. The command was assembleDebug. The project is a library module (Kotlin and one Java file) and an app module (Kotlin) that uses it. The plugin and Kotlin compiler are downloaded at run time and are not checksum-pinned.
How: one Gradle home was shared for downloads and Gradle's transform results, and a build with the cache off filled it first. Every build used a fresh copy of the project and no local build cache. Of the 78 tasks, 12 had nothing to run or were already up to date, so they could not be restored. The project is generated and small, with no real dependencies.
Not tested: Android release builds, lint, Android tests, Kotlin Multiplatform, kapt or KSP, Compose, a real-sized app, other plugin versions, Maven. The Kotlin JVM runs were on a Mac and the Android runs on the hosted machine. We make no claim about build times.