Using Gradle build cache with Kotlin

Table of Contents

  • Enabling the build cache for your projects
  • Enabling build caching in IntelliJ
  • Caching kapt tasks
  • Further reading
  • Conclusion
  • Introduction

    A build cache allows Gradle to reuse task output from any previous invocation, including those from other machines. Kotlin 1.2.21 allows Kotlin projects to make use of build caching.

    The build cache works by storing compiled classes, test outputs, and other build artifacts in a cache, taking into account all task inputs, including input file contents, relevant classpaths, and task configuration.

    Build Cache topological diagram

    This frequently results in faster builds. The following chart shows aggregated build time with and without the build cache for part of Gradle’s CI:

    Build minutes saved with Gradle build cache

    In this post, we’ll explain how you can use Gradle’s build cache to avoid unnecessary Kotlin compilation to speed up your builds.

    Quick demo with Spek #

    You can try out build caching with Gradle right now. Just follow these steps:

    Clone Spek #

    git clone https://github.com/spekframework/spek.git
    cd spek
    

    The Spek 2.x branch (which is the default) already has all prerequisites for build caching that we’ll describe later.

    Build and populate cache #

    The following command builds Spek and populates the local build cache.

    ❯ ./gradlew assemble --build-cache
    
    BUILD SUCCESSFUL in 10s
    21 actionable tasks: 21 executed
    

    Using the --build-cache flag is one way to tell Gradle to store outputs in a separate task output cache.

    Remove/change build outputs #

    This simulates being on another machine or perhaps making a change and stashing it. The quickest way to demonstrate is use the clean task.

    ❯ ./gradlew clean
    

    Re-build and resolve from build cache #

    This time when we re-build, all Kotlin compiled sources are pulled from the build cache.

    ❯ ./gradlew assemble --build-cache
    
    BUILD SUCCESSFUL in 2s
    21 actionable tasks: 11 executed, 10 from cache
    

    Voilà! You just used Gradle’s build cache to reuse Kotlin compiled classes instead of recompiling again! The build was about 5x faster!

    You can see from this build scan that Kotlin compile tasks were pulled from the build cache; :jar and :processResources tasks were not because it’s faster to generate JARs and copy files locally than pull from a cache. Note that caching :test tasks is also supported.

    The Gradle build cache is particularly effective when a CI instance populates a shared build cache, which developers can pull from. Links to more resources for achieving this are listed below.

    Enabling the build cache for your projects #

    I hope you’re excited to try this out on your project — you can follow these steps to enable the build cache.

    First, you need to ensure you’re using Gradle 4.3 or above, so the Kotlin Gradle Plugin can opt-in to using new APIs in Gradle. You can upgrade Gradle easily using the Gradle wrapper.

    Next, we need to ensure we are compiling with Kotlin version 1.2.20 or above. You might have something like this declared in your buildscript {} block in build.gradle:

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.21"
    }
    

    Next, we need to tell Gradle to use the build cache. There are 3 ways to do this:

    • Enable for the current build using --build-cache on the command-line.
    • Enable for the project by adding org.gradle.caching=true to $PROJECT_ROOT/gradle.properties.
    • Enable for all builds for the current user by adding org.gradle.caching=true to $GRADLE_HOME/gradle.properties.

    NOTE: Android developers still need to do this even if android.enableBuildCache=true is set, because Gradle’s build cache is separate from the Android build cache.

    We can optionally take advantage of the build cache from IDEs by delegating run and test actions to Gradle.

    Enabling build caching in IntelliJ #

    If you use IntelliJ to execute Gradle actions, you will need to “Delegate IDE build/run actions to Gradle” in your IDE settings to take advantage of build caching when building and running tests from IntelliJ.

    Delegate IDE build/run to Gradle

    NOTE: Android Studio does this by default.

    Caching kapt tasks #

    Caching for kapt is currently disabled by default, even with --build-cache, because Gradle does not yet have a way to map inputs and outputs for annotation processors. You can explicitly enable use of the build cache for Kotlin annotation processing tasks by setting useBuildCache to true in kapt configuration.

    kapt {
        useBuildCache = true
    }
    

    Further reading #

    You can learn more about leveraging the Gradle build cache through these resources:

    Conclusion #

    Compiling Kotlin code using kotlin-gradle-plugin version 1.2.20 and above can take advantage of Gradle’s --build-cache feature to speed up your development cycle. Work continues to expand the set of tasks that support build caching.

    Onward!

    Discuss