|
| 1 | +[//]: # (title: Gradle best practices) |
| 2 | + |
| 3 | +[Gradle](https://docs.gradle.org/current/userguide/userguide.html) is a build system used by many Kotlin projects to automate |
| 4 | +and manage the build process. |
| 5 | + |
| 6 | +Getting the best out of Gradle is essential to help you spend less time managing and waiting for builds, and more time |
| 7 | +coding. Here we provide a set of best practices split into two key areas: **organizing** and **optimizing** your projects. |
| 8 | + |
| 9 | +## Organize |
| 10 | + |
| 11 | +This section focuses on structuring your Gradle projects to improve clarity, maintainability, and scalability. |
| 12 | + |
| 13 | +### Use Kotlin DSL |
| 14 | + |
| 15 | +Use Kotlin DSL instead of the traditional Groovy DSL. You avoid learning another language and gain the benefits of strict |
| 16 | +typing. Strict typing lets IDEs provide better support for refactoring and auto-completion, making development more efficient. |
| 17 | + |
| 18 | +Find more information in [Gradle’s Kotlin DSL primer](https://docs.gradle.org/current/userguide/kotlin_dsl.html). |
| 19 | + |
| 20 | +Read Gradle's [blog](https://blog.gradle.org/kotlin-dsl-is-now-the-default-for-new-gradle-builds) about Kotlin DSL becoming |
| 21 | +the default for Gradle builds. |
| 22 | + |
| 23 | +### Use a version catalog |
| 24 | + |
| 25 | +Use a version catalog in a `libs.versions.toml` file to centralize dependency management. This enables you to define and |
| 26 | +reuse versions, libraries, and plugins consistently across projects. |
| 27 | + |
| 28 | +```kotlin |
| 29 | +[versions] |
| 30 | +kotlinxCoroutines = "%coroutinesVersion%" |
| 31 | + |
| 32 | +[libraries] |
| 33 | +kotlinxCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } |
| 34 | +``` |
| 35 | + |
| 36 | +With the following dependency added to your `build.gradle.kts` file: |
| 37 | + |
| 38 | +```kotlin |
| 39 | +dependencies { |
| 40 | + implementation(libs.kotlinxCoroutines) |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +Learn more in Gradle's documentation about [Dependency management basics](https://docs.gradle.org/current/userguide/dependency_management_basics.html#version_catalog). |
| 45 | + |
| 46 | +### Use convention plugins |
| 47 | + |
| 48 | +<primary-label ref="advanced"/> |
| 49 | + |
| 50 | +Use convention plugins to encapsulate and reuse common build logic across multiple build files. Moving shared configurations |
| 51 | +into a plugin helps simplify and modularize your build scripts. |
| 52 | + |
| 53 | +Although the initial setup may be time-consuming, it's easy to maintain and add new build logic once you complete it. |
| 54 | + |
| 55 | +Learn more in Gradle's documentation about [Convention plugins](https://docs.gradle.org/current/userguide/custom_plugins.html#sec:convention_plugins). |
| 56 | + |
| 57 | +## Optimize |
| 58 | + |
| 59 | +This section provides strategies to enhance the performance and efficiency of your Gradle builds. |
| 60 | + |
| 61 | +### Use local build cache |
| 62 | + |
| 63 | +Use a local build cache to save time by reusing outputs produced by other builds. The build cache can retrieve outputs from |
| 64 | +any earlier build that you have already created. |
| 65 | + |
| 66 | +Learn more in Gradle's documentation about their [Build cache](https://docs.gradle.org/current/userguide/build_cache.html). |
| 67 | + |
| 68 | +### Use configuration cache |
| 69 | + |
| 70 | +> The configuration cache doesn't support all core Gradle plugins yet. For the latest information, see Gradle's |
| 71 | +> [table of supported plugins](https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:plugins:core). |
| 72 | +> |
| 73 | +{style="note"} |
| 74 | + |
| 75 | +Use the configuration cache to significantly improve build performance by caching the result of the configuration phase |
| 76 | +and reuse it for subsequent builds. If nothing changes in a build file (or its dependencies) the build file isn't |
| 77 | +recompiled. |
| 78 | + |
| 79 | +Learn more in Gradle's documentation about their [Configuration cache](https://docs.gradle.org/current/userguide/configuration_cache.html). |
| 80 | + |
| 81 | +### Improve build times for multiple targets |
| 82 | + |
| 83 | +When your multiplatform project includes multiple targets, tasks like `build` and `assemble` can compile the same code |
| 84 | +multiple times for each target, leading to longer compilation times. |
| 85 | + |
| 86 | +If you're actively developing and testing a specific platform, run the corresponding `linkDebug*` task instead. |
| 87 | + |
| 88 | +For more information, see [Tips for improving compilation time](native-improving-compilation-time.md#gradle-configuration). |
| 89 | + |
| 90 | +### Migrate from kapt to KSP |
| 91 | + |
| 92 | +If you're using a library that relies on the [kapt](kapt.md) compiler plugin, check whether you can switch to using the [Kotlin Symbol Processing (KSP) API](ksp-overview.md) |
| 93 | +instead. The KSP API improves build performance by reducing annotation processing time. KSP is faster and more efficient |
| 94 | +than kapt, as it processes source code directly without generating intermediary Java stubs. |
| 95 | + |
| 96 | +To learn more about how KSP compares to kapt, check out [why KSP](ksp-why-ksp.md). |
| 97 | + |
| 98 | +### Use modularization |
| 99 | + |
| 100 | +<primary-label ref="advanced"/> |
| 101 | + |
| 102 | +> Modularization only benefits projects of moderate to large size. It doesn't provide advantages for projects based |
| 103 | +> on a microservices architecture. |
| 104 | +> |
| 105 | +{style="note"} |
| 106 | + |
| 107 | +Use a modularized project structure to increase build speed and enable easier parallel development. Structure your |
| 108 | +project into one root project and one or more subprojects. If changes only affect one of the subprojects, Gradle |
| 109 | +rebuilds only that specific subproject. |
| 110 | + |
| 111 | +```none |
| 112 | +. |
| 113 | +└── root-project/ |
| 114 | + ├── settings.gradle.kts |
| 115 | + ├── app subproject/ |
| 116 | + │ └── build.gradle.kts |
| 117 | + └── lib subproject/ |
| 118 | + └── build.gradle.kts |
| 119 | +``` |
| 120 | + |
| 121 | +Learn more in Gradle's documentation about [Structuring projects with Gradle](https://docs.gradle.org/current/userguide/multi_project_builds.html). |
| 122 | + |
| 123 | +### Set up CI/CD |
| 124 | +<primary-label ref="advanced"/> |
| 125 | + |
| 126 | +Set up a CI/CD process to significantly reduce build time by using incremental builds and caching dependencies. Add |
| 127 | +persistent storage or use a remote build cache to see these benefits. This process doesn't have to be time-consuming, |
| 128 | +as some providers, like [GitHub](https://github.com/features/actions), offer this service almost out of the box. |
| 129 | + |
| 130 | +Explore Gradle's community cookbook on [Using Gradle with Continuous Integration systems](https://community.gradle.org/cookbook/ci/). |
| 131 | + |
| 132 | +### Use remote build cache |
| 133 | +<primary-label ref="advanced"/> |
| 134 | + |
| 135 | +Like the [local build cache](#use-local-build-cache), the remote build cache helps you save time by reusing outputs |
| 136 | +from other builds. It can retrieve task outputs from any earlier build you've already run, not just the last one. |
| 137 | + |
| 138 | +The remote build cache uses a cache server to share task outputs across builds. For example, in a development environment |
| 139 | +with a CI/CD server, all builds on the server populate the remote cache. When you check out the main branch to |
| 140 | +start a new feature, you can immediately access incremental builds. |
| 141 | + |
| 142 | +Keep in mind that a slow internet connection might make transferring cached results slower than running tasks locally. |
| 143 | + |
| 144 | +Learn more in Gradle's documentation about their [Build cache](https://docs.gradle.org/current/userguide/build_cache.html). |
0 commit comments