The Gradle Kotlin DSL: build.gradle.kts
Type-safe, IDE-autocompleted builds that replace the old Groovy build.gradle.
Gradle is the build tool that compiles your Kotlin code, resolves your dependencies, runs your tests, and packages your application. Historically you described all of this in a file named build.gradle written in Groovy, a dynamic JVM language. Groovy is flexible and concise, but that flexibility comes at a cost: the build script is essentially untyped, so a misspelled method or a wrong property name is only discovered when the build actually runs, and your IDE can offer little more than guesswork for autocompletion. The Kotlin DSL changes the file name to build.gradle.kts and writes the same configuration in Kotlin instead.
Because build.gradle.kts is real Kotlin, the entire Gradle API becomes statically typed. Your IDE (IntelliJ IDEA or Android Studio give the richest support) can autocomplete plugin names, configuration blocks, dependency methods, and task properties; it underlines typos in red before you ever press run; and Ctrl/Cmd-click jumps straight into Gradle's source or KDoc. Errors that used to surface as cryptic runtime failures now appear as ordinary compile errors with precise line numbers. The trade-off is that the very first configuration after a change is a little slower because the script must be compiled, but Gradle caches the compiled script aggressively, so day-to-day editing stays fast and the safety is well worth it.
Every Kotlin DSL build script is organized around a few core blocks. The plugins {} block declares which Gradle plugins to apply, such as the Kotlin JVM plugin or the application plugin; each plugin contributes new tasks and configuration options. The repositories {} block tells Gradle where to download dependencies from, almost always mavenCentral() and sometimes google() for Android. The dependencies {} block lists the libraries your project needs, grouped by configuration: implementation for code you use internally, api for dependencies you expose to consumers (available once the java-library plugin is applied), and testImplementation for test-only libraries like JUnit or Kotest. These blocks are just regular Kotlin function calls with trailing lambdas, which is why the IDE understands them so well.
Notice the small syntax differences from Groovy. The Kotlin DSL requires double quotes for strings and parentheses around method arguments, so a dependency is written implementation("group:artifact:version") rather than Groovy's implementation 'group:artifact:version'. Assignments use a clear = (for example version = "1.0.0"), and plugin versions are declared with the version("...") infix call inside plugins {}. These rules make the script more verbose than Groovy in places, but they are exactly what gives the compiler enough information to validate everything and to power autocompletion.
Alongside build.gradle.kts there are two other files worth knowing. settings.gradle.kts is the entry point of the build: it sets the root project name and, in a multi-module build, lists every subproject with include("..."). The modern way to manage dependency versions is a version catalog, a TOML file at gradle/libs.versions.toml that centralizes versions, libraries, and plugins in one place. You then reference them in build.gradle.kts through the generated, type-safe libs accessor, for example implementation(libs.kotlinx.coroutines.core), so a version bump happens in exactly one file and the IDE autocompletes every alias.
In short, the Kotlin DSL gives you a build description written in the same language as your application, with full type safety, refactoring support, and autocompletion. For a Kotlin developer it removes the context switch into an untyped Groovy world and turns the build script into a first-class, navigable part of the codebase. New Kotlin and Android projects are scaffolded with the Kotlin DSL by default, and combining it with a version catalog is the recommended setup for any modern Gradle 8 project running Kotlin 2.x.
// build.gradle.kts โ a typical Kotlin JVM application moduleplugins {kotlin("jvm") version "2.0.21" // Kotlin JVM plugin, version via infix callapplication // adds the `run` task}repositories {mavenCentral() // where Gradle downloads dependencies from}dependencies {implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") // internal usetestImplementation(kotlin("test")) // test-only dependency (JUnit-based)}application {mainClass = "com.example.MainKt" // type-safe assignment with `=`}
A complete, idiomatic build.gradle.kts: plugins, repositories, dependencies, and a typed task config.
// settings.gradle.kts โ the entry point of the buildrootProject.name = "my-app" // names the root projectinclude("core", "web") // declares two subprojects in a multi-module build
settings.gradle.kts sets the project name and registers every module.
# gradle/libs.versions.toml โ centralized version catalog[versions]kotlin = "2.0.21"coroutines = "1.9.0"[libraries]kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }[plugins]kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }# In build.gradle.kts: implementation(libs.kotlinx.coroutines.core) and alias(libs.plugins.kotlin.jvm)
A version catalog centralizes versions; the generated `libs` accessor is type-safe and autocompleted.
๐ง Check your understanding
0/1 ยท 0/1 answered1. What is the main advantage of build.gradle.kts (Kotlin DSL) over the old Groovy build.gradle?