← All release notes
KotlinKotlin 2.0May 28, 2024 · 5 min read

Kotlin 2.0 and the K2 Compiler

Kotlin 2.0 makes the K2 compiler the default, moves the Compose compiler into the Kotlin repo, and speeds up the IDE.

Kotlin 2.0 is a compiler rewrite shipping as a point release, not a language release. Syntax barely moves. What compiles that syntax changed completely: K2, the new frontend, becomes the default across JVM and Android, and it drags one very Android-specific dependency along with it, the Compose compiler.

#K2 is the default compiler

K2 replaces the old compiler frontend with a rewritten one built for faster compilation and for consistent behavior across every Kotlin target. Most codebases notice nothing beyond shorter builds. K2 compiles the same valid code the same way, by design. Risk lives at the margins: code leaning on old-frontend quirks, or on compiler-specific edge-case behavior, can behave differently under the new frontend, and dealing with that is a recompile-and-test pass rather than a rewrite.

plugins {
    kotlin("jvm") version "2.0.0"
}

Use it when: you upgrade the Kotlin Gradle plugin version. No separate opt-in exists. K2 is what "Kotlin 2.0" means for the JVM and Android targets.

#Smarter, more consistent smart casts

Old-frontend smart casting bailed out in cases where it could reasonably have narrowed a type, most visibly around local variables and control flow with more than one branch. K2's rewritten type inference and data-flow analysis close a number of those.

Your mental model doesn't change. Null-check or type-check a value and the compiler treats it as non-null or narrowed inside the branches where that's provably true.

fun describe(value: Any?): String {
    if (value == null) return "nothing"
    return when (value) {
        is String -> "string of length ${value.length}"
        is Int -> "int: $value"
        else -> "other: $value"
    }
}

#The Compose compiler moves into the Kotlin repo

Until Kotlin 2.0 the Jetpack Compose compiler plugin shipped and versioned separately from Kotlin, which meant pinning a specific Compose compiler version to a specific Kotlin version and reading a compatibility table before every single upgrade.

That split is over. JetBrains owns the plugin now, ships it directly from the Kotlin repository, and versions it alongside the language itself.

plugins {
    kotlin("android") version "2.0.0"
    id("org.jetbrains.kotlin.plugin.compose") version "2.0.0"
}

Use it when: any Android project using Jetpack Compose. Delete the old composeOptions { kotlinCompilerExtensionVersion } block. This plugin replaces it, and the compatibility-table problem that block existed to solve goes away with it.

#Faster IDE analysis

Android Studio's Kotlin plugin runs on that same K2 frontend, so code analysis, autocomplete, and error highlighting get materially faster on large projects. None of that is a feature. It falls out of unifying the compiler and IDE analysis engine, and for a team upgrading it's often the most noticeable day-to-day change of the whole release.

#Migration reality

Most of this migration is mechanical. Bump the Kotlin Gradle plugin, apply the new Compose compiler plugin if you use Compose, remove the old kotlinCompilerExtensionVersion pin, run your full test suite.

Breakage shows up somewhere else entirely: annotation processors and Gradle plugins that reach into Kotlin compiler internals directly rather than going through public APIs. Depend on kapt-heavy code generation? Budget extra verification time rather than assuming a clean upgrade.

#What to adopt first

  • Bump the Kotlin Gradle plugin to 2.0 first, on its own, before touching anything else. Highest value, lowest risk. IDE speed gains ride on that one bump.
  • Move to the standalone Compose compiler plugin in the same pass if you use Compose. Leaving the old kotlinCompilerExtensionVersion block in place next to Kotlin 2.0 is the most common source of confusing build errors during this migration.
  • Don't rewrite code to "use K2 features". There are no new language features here, only a new compiler, and the upgrade should stay invisible to your source outside the Gradle files.
  • Run your full test suite before and after. Watch anything kapt-based, since that's where compiler-internal assumptions are most likely to live.