Configure a Gradle project
To build a Kotlin project with Gradle, you need to add the Kotlin Gradle plugin to your build script file build.gradle(.kts)
and configure the project's dependencies there.
Apply the plugin
To apply the Kotlin Gradle plugin, use the plugins{}
block from the Gradle plugins DSL:
When configuring your project, check the Kotlin Gradle plugin (KGP) compatibility with available Gradle versions. In the following table, there are the minimum and maximum fully supported versions of Gradle and Android Gradle plugin (AGP):
KGP version | Gradle min and max versions | AGP min and max versions |
---|---|---|
2.0.20 | 6.8.3–8.8* | 7.1.3–8.5 |
2.0.0 | 6.8.3–8.5 | 7.1.3–8.3.1 |
1.9.20–1.9.25 | 6.8.3–8.1.1 | 4.2.2–8.1.0 |
1.9.0–1.9.10 | 6.8.3–7.6.0 | 4.2.2–7.4.0 |
1.8.20–1.8.22 | 6.8.3–7.6.0 | 4.1.3–7.4.0 |
1.8.0–1.8.11 | 6.8.3–7.3.3 | 4.1.3–7.2.1 |
1.7.20–1.7.22 | 6.7.1–7.1.1 | 3.6.4–7.0.4 |
1.7.0–1.7.10 | 6.7.1–7.0.2 | 3.4.3–7.0.2 |
1.6.20–1.6.21 | 6.1.1–7.0.2 | 3.4.3–7.0.2 |
You can also use Gradle and AGP versions up to the latest releases, but if you do, keep in mind that you might encounter deprecation warnings or some new features might not work.
For example, the Kotlin Gradle plugin and the kotlin-multiplatform
plugin 2.0.20 require the minimum Gradle version of 6.8.3 for your project to compile.
Similarly, the maximum fully supported version is 8.8. It doesn't have deprecated Gradle methods and properties, and supports all the current Gradle features.
Kotlin Gradle plugin data in a project
By default, the Kotlin Gradle plugin stores persistent project-specific data at the root of the project, in the .kotlin
directory.
There are properties you can add to the gradle.properties
file of your project to configure this behavior:
Gradle property | Description |
---|---|
| Configures the location where your project-level data is stored. Default: |
| Controls whether writing Kotlin data to the |
Targeting the JVM
To target the JVM, apply the Kotlin JVM plugin.
The version
should be literal in this block, and it cannot be applied from another build script.
Kotlin and Java sources
Kotlin sources and Java sources can be stored in the same directory, or they can be placed in different directories.
The default convention is to use different directories:
The corresponding sourceSets
property should be updated if you are not using the default convention:
Check for JVM target compatibility of related compile tasks
In the build module, you may have related compile tasks, for example:
compileKotlin
andcompileJava
compileTestKotlin
andcompileTestJava
For related tasks like these, the Kotlin Gradle plugin checks for JVM target compatibility. Different values of the jvmTarget
attribute in the kotlin
extension or task and targetCompatibility
in the java
extension or task cause JVM target incompatibility. For example: the compileKotlin
task has jvmTarget=1.8
, and the compileJava
task has (or inherits) targetCompatibility=15
.
Configure the behavior of this check for the whole project by setting the kotlin.jvm.target.validation.mode
property in the build.gradle(.kts)
file to:
error
– the plugin fails the build; the default value for projects on Gradle 8.0+.warning
– the plugin prints a warning message; the default value for projects on Gradle less than 8.0.ignore
– the plugin skips the check and doesn't produce any messages.
You can also configure it at task level in your build.gradle(.kts)
file:
To avoid JVM target incompatibility, configure a toolchain or align JVM versions manually.
What can go wrong if targets are incompatible
There are two ways of manually setting JVM targets for Kotlin and Java source sets:
The implicit way via setting up a Java toolchain.
The explicit way via setting the
jvmTarget
attribute in thekotlin
extension or task andtargetCompatibility
in thejava
extension or task.
JVM target incompatibility occurs if you:
Explicitly set different values of
jvmTarget
andtargetCompatibility
.Have a default configuration, and your JDK is not equal to
1.8
.
Let's consider a default configuration of JVM targets when you have only the Kotlin JVM plugin in your build script and no additional settings for JVM targets:
When there is no explicit information about the jvmTarget
value in the build script, its default value is null
, and the compiler translates it to the default value 1.8
. The targetCompatibility
equals the current Gradle's JDK version, which is equal to your JDK version (unless you use a Java toolchain approach). Assuming that your JDK version is 17
, your published library artifact will declare itself compatible with JDK 17+: org.gradle.jvm.version=17
, which is wrong. In this case, you have to use Java 17 in your main project to add this library, even though the bytecode's version is 1.8
. Configure a toolchain to solve this issue.
Gradle Java toolchains support
Gradle 6.7 introduced Java toolchains support. Using this feature, you can:
Use a JDK and a JRE that are different from the ones in Gradle to run compilations, tests, and executables.
Compile and test code with a not-yet-released language version.
With toolchains support, Gradle can autodetect local JDKs and install missing JDKs that Gradle requires for the build. Now Gradle itself can run on any JDK and still reuse the remote build cache feature for tasks that depend on a major JDK version.
The Kotlin Gradle plugin supports Java toolchains for Kotlin/JVM compilation tasks. JS and Native tasks don't use toolchains. The Kotlin compiler always runs on the JDK the Gradle daemon is running on. A Java toolchain:
Sets the
-jdk-home
option available for JVM targets.Sets the
compilerOptions.jvmTarget
to the toolchain's JDK version if the user doesn't set thejvmTarget
option explicitly. If the user doesn't configure the toolchain, thejvmTarget
field uses the default value. Learn more about JVM target compatibility.Sets the toolchain to be used by any Java compile, test and javadoc tasks.
Affects which JDK
kapt
workers are running on.
Use the following code to set a toolchain. Replace the placeholder <MAJOR_JDK_VERSION>
with the JDK version you would like to use:
Note that setting a toolchain via the kotlin
extension updates the toolchain for Java compile tasks as well.
You can set a toolchain via the java
extension, and Kotlin compilation tasks will use it:
If you use Gradle 8.0.2 or higher, you also need to add a toolchain resolver plugin. This type of plugin manages which repositories to download a toolchain from. As an example, add to your settings.gradle(.kts)
the following plugin:
Check that the version of foojay-resolver-convention
corresponds to your Gradle version on the Gradle site.
To set any JDK (even local) for a specific task, use the Task DSL.
Learn more about Gradle JVM toolchain support in the Kotlin plugin.
Set JDK version with the Task DSL
The Task DSL allows setting any JDK version for any task implementing the UsesKotlinJavaToolchain
interface. At the moment, these tasks are KotlinCompile
and KaptTask
. If you want Gradle to search for the major JDK version, replace the <MAJOR_JDK_VERSION>
placeholder in your build script:
Or you can specify the path to your local JDK and replace the placeholder <LOCAL_JDK_VERSION>
with this JDK version:
Associate compiler tasks
You can associate compilations by setting up such a relationship between them that one compilation uses the compiled outputs of the other. Associating compilations establishes internal
visibility between them.
The Kotlin compiler associates some compilations by default, such as the test
and main
compilations of each target. If you need to express that one of your custom compilations is connected to another, create your own associated compilation.
To make the IDE support associated compilations for inferring visibility between source sets, add the following code to your build.gradle(.kts)
:
Here, the integrationTest
compilation is associated with the main
compilation that gives access to internal
objects from functional tests.
Configure with Java Modules (JPMS) enabled
To make the Kotlin Gradle plugin work with Java Modules, add the following lines to your build script and replace YOUR_MODULE_NAME
with a reference to your JPMS module, for example, org.company.module
:
Learn more about:
Other details
Learn more about Kotlin/JVM.
Disable use of artifact in compilation task
In some rare scenarios, you can experience a build failure caused by a circular dependency error. For example, when you have multiple compilations where one compilation can see all internal declarations of another, and the generated artifact relies on the output of both compilation tasks:
To fix this circular dependency error, we've added a Gradle property: archivesTaskOutputAsFriendModule
. This property controls the use of artifact inputs in the compilation task and determines if a task dependency is created as a result.
By default, this property is set to true
to track the task dependency. If you encounter a circular dependency error, you can disable the use of the artifact in the compilation task to remove the task dependency and avoid the circular dependency error.
To disable the use of the artifact in the compilation task, add the following to your gradle.properties
file:
Lazy Kotlin/JVM task creation
Starting from Kotlin 1.8.20, the Kotlin Gradle plugin registers all tasks and doesn't configure them on a dry run.
Non-default location of compile tasks' destinationDirectory
If you override the Kotlin/JVM KotlinJvmCompile
/KotlinCompile
task's destinationDirectory
location, update your build script. You need to explicitly add sourceSets.main.kotlin.classesDirectories
to sourceSets.main.outputs
in your JAR file:
Targeting multiple platforms
Projects targeting multiple platforms, called multiplatform projects, require the kotlin-multiplatform
plugin.
Learn more about Kotlin Multiplatform for different platforms and Kotlin Multiplatform for iOS and Android.
Targeting Android
It's recommended to use Android Studio for creating Android applications. Learn how to use the Android Gradle plugin.
Targeting JavaScript
When targeting JavaScript, use the kotlin-multiplatform
plugin as well. Learn more about setting up a Kotlin/JS project
Kotlin and Java sources for JavaScript
This plugin only works for Kotlin files, so it is recommended that you keep Kotlin and Java files separate (if the project contains Java files). If you don't store them separately, specify the source folder in the sourceSets{}
block:
Triggering configuration actions with the KotlinBasePlugin interface
To trigger some configuration action whenever any Kotlin Gradle plugin (JVM, JS, Multiplatform, Native, and others) is applied, use the KotlinBasePlugin
interface that all Kotlin plugins inherit from:
Configure dependencies
To add a dependency on a library, set the dependency of the required type (for example, implementation
) in the dependencies{}
block of the source sets DSL.
Alternatively, you can set dependencies at top level.
Dependency types
Choose the dependency type based on your requirements.
Type | Description | When to use |
---|---|---|
| Used both during compilation and at runtime and is exported to library consumers. | If any type from a dependency is used in the public API of the current module, use an |
| Used during compilation and at runtime for the current module, but is not exposed for compilation of other modules depending on the one with the `implementation` dependency. | Use for dependencies needed for the internal logic of a module. If a module is an endpoint application which is not published, use |
| Used for compilation of the current module and is not available at runtime nor during compilation of other modules. | Use for APIs which have a third-party implementation available at runtime. |
| Available at runtime but is not visible during compilation of any module. |
Dependency on the standard library
A dependency on the standard library (stdlib
) is added automatically to each source set. The version of the standard library used is the same as the version of the Kotlin Gradle plugin.
For platform-specific source sets, the corresponding platform-specific variant of the library is used, while a common standard library is added to the rest. The Kotlin Gradle plugin selects the appropriate JVM standard library depending on the compilerOptions.jvmTarget
compiler option of your Gradle build script.
If you declare a standard library dependency explicitly (for example, if you need a different version), the Kotlin Gradle plugin won't override it or add a second standard library.
If you don't need a standard library at all, you can add the following Gradle property to your gradle.properties
file:
Versions alignment of transitive dependencies
From Kotlin standard library version 1.9.20, Gradle uses metadata included in the standard library to automatically align transitive kotlin-stdlib-jdk7
and kotlin-stdlib-jdk8
dependencies.
If you add a dependency for any Kotlin standard library version between 1.8.0 – 1.9.10, for example: implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.0")
, then the Kotlin Gradle Plugin uses this Kotlin version for transitive kotlin-stdlib-jdk7
and kotlin-stdlib-jdk8
dependencies. This avoids class duplication from different standard library versions. Learn more about merging kotlin-stdlib-jdk7
and kotlin-stdlib-jdk8
into kotlin-stdlib
. You can disable this behavior with the kotlin.stdlib.jdk.variants.version.alignment
Gradle property in your gradle.properties
file:
Other ways to align versions
If you have issues with version alignment, you can align all versions via the Kotlin BOM. Declare a platform dependency on
kotlin-bom
in your build script:implementation(platform("org.jetbrains.kotlin:kotlin-bom:2.0.20"))implementation platform('org.jetbrains.kotlin:kotlin-bom:2.0.20')If you don't add a dependency for a standard library version, but you have two different dependencies that transitively bring different old versions of the Kotlin standard library, then you can explicitly require
2.0.20
versions of these transitive libraries:dependencies { constraints { add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk7") { version { require("2.0.20") } } add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8") { version { require("2.0.20") } } } }dependencies { constraints { add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk7") { version { require("2.0.20") } } add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk8") { version { require("2.0.20") } } } }If you add a dependency for Kotlin standard library version
2.0.20
:implementation("org.jetbrains.kotlin:kotlin-stdlib:2.0.20")
, and an old version (earlier than1.8.0
) of the Kotlin Gradle plugin, update the Kotlin Gradle plugin to match the standard library version:plugins { // replace `<...>` with the plugin name kotlin("<...>") version "2.0.20" }plugins { // replace `<...>` with the plugin name id "org.jetbrains.kotlin.<...>" version "2.0.20" }If you use versions prior to
1.8.0
ofkotlin-stdlib-jdk7
/kotlin-stdlib-jdk8
, for example,implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:SOME_OLD_KOTLIN_VERSION")
, and a dependency that transitively bringskotlin-stdlib:1.8+
, replace yourkotlin-stdlib-jdk<7/8>:SOME_OLD_KOTLIN_VERSION
withkotlin-stdlib-jdk*:2.0.20
or exclude the transitivekotlin-stdlib:1.8+
from the library that brings it:dependencies { implementation("com.example:lib:1.0") { exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib") } }dependencies { implementation("com.example:lib:1.0") { exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib" } }
Set dependencies on test libraries
The kotlin.test
API is available for testing Kotlin projects on all supported platforms. Add the kotlin-test
dependency to the commonTest
source set, so that the Gradle plugin can infer the corresponding test dependencies for each test source set.
Kotlin/Native targets do not require additional test dependencies, and the kotlin.test
API implementations are built-in.
You can use the kotlin-test
dependency in any shared or platform-specific source set as well.
JVM variants of kotlin-test
For Kotlin/JVM, Gradle uses JUnit 4 by default. Therefore, the kotlin("test")
dependency resolves to the variant for JUnit 4, namely kotlin-test-junit
.
You can choose JUnit 5 or TestNG by calling useJUnitPlatform()
or useTestNG()
in the test task of your build script. The following example is for a Kotlin Multiplatform project:
The following example is for a JVM project:
Learn how to test code using JUnit on the JVM.
Automatic JVM variant resolution can sometimes cause problems for your configuration. In that case, you can specify the necessary framework explicitly and disable the automatic resolution by adding this line to the project gradle.properties
file:
If you have used a variant of kotlin("test")
in your build script explicitly and your project build stopped working with a compatibility conflict, see this issue in the Compatibility Guide.
Set a dependency on a kotlinx library
If you use a kotlinx
library and need a platform-specific dependency, you can use platform-specific variants of libraries with suffixes such as -jvm
or -js
, for example, kotlinx-coroutines-core-jvm
. You can also use the library's base artifact name instead – kotlinx-coroutines-core
.
If you use a multiplatform library and need to depend on the shared code, set the dependency only once, in the shared source set. Use the library's base artifact name, such as kotlinx-coroutines-core
or ktor-client-core
.
Set dependencies at top level
Alternatively, you can specify the dependencies at top level, using the following pattern for the configuration names: <sourceSetName><DependencyType>
. This can be helpful for some Gradle built-in dependencies, like gradleApi()
, localGroovy()
, or gradleTestKit()
, which are not available in the source sets' dependency DSL.
Declare repositories
You can declare a publicly-available repository to use its open source dependencies. In the repositories{}
block, set the name of the repository:
Popular repositories are Maven Central and Google's Maven repository.
If you need to declare the same repositories in more than one subproject, declare the repositories centrally in the dependencyResolutionManagement{}
block in your settings.gradle(.kts)
file:
Any declared repositories in subprojects override repositories declared centrally. For more information on how to control this behavior and what options are available, see Gradle's documentation.
What's next?
Learn more about: