Kotlin 2.4.20 dropped on September 7 and it is not a milestone release — which is precisely why it will catch teams off guard. Three changes break existing code (one is now a compile error), sealed classes finally produce exhaustive Swift enums, and the Kotlin runner has a new name. Here is what to fix today and what you are actually getting in return.
The Feature KMP iOS Teams Have Been Waiting For
Swift export for sealed classes is the headline addition in Kotlin 2.4.20. Sealed interfaces and classes now map to Swift enums via a generated sealedType() method, which means Swift callers get full compiler-enforced exhaustiveness — no more @unknown default hacks to satisfy the switch checker.
// Kotlin
sealed interface NetworkResult
data class Success(val data: String) : NetworkResult
data class Failure(val error: Exception) : NetworkResult
// Swift (generated interop)
let result = fetchData()
switch result.sealedType() {
case let .success(s): render(s.value.data)
case let .failure(f): showError(f.value.error.message)
// Add a case to NetworkResult in Kotlin — Swift compiler flags this switch immediately
}
This is not a small quality-of-life improvement. The third-party SKIE library from Touchlab has been papering over this gap for two years. With native support in the Kotlin compiler, teams can drop that dependency for this use case. Cross-language inheritance is also new: Swift classes can now implement Kotlin interfaces directly, enabling the reverse-import pattern without Objective-C intermediaries.
The assembleSharedXCFramework task now auto-generates Package.swift files for SwiftPM dependencies — previously maintained by hand, a footgun for teams that forgot to update it after adding a module. KMP adoption hit 23% of professional developers in 2026, up from 7% two years ago. The iOS interop story is a large part of why that number is climbing, and 2.4.20 makes it meaningfully cleaner.
Three Things to Fix Before You Update
1. Rename kotlin to kotlinr in CI
The Kotlin runner command is now kotlinr. The rename exists to avoid a naming conflict with the Kotlin Toolchain’s own kotlin command. The old kotlin command still works in 2.4.20 but emits a deprecation warning. It will not work indefinitely.
Audit shell scripts, Dockerfiles, Makefiles, and CI YAML files. A quick grep surfaces most of them:
grep -rn "kotlin " .github/ scripts/ Dockerfile Makefile 2>/dev/null
JetBrains should have caught this naming collision before Kotlin Toolchain shipped. The fix is mechanical — just do it now rather than waiting for the eventual hard break.
2. Replace @JsFun top-level require() calls
Previously a warning, now a compile error. Top-level require() inside @JsFun declarations will block your Kotlin/JS or Kotlin/Wasm build.
// Before — compile error in 2.4.20
@JsFun("require('axios')") external fun loadAxios(): dynamic
// After
@JsModule("axios")
external val axios: dynamic
The @JsModule pattern was always the correct approach. This change just enforces it.
3. Audit companion object initialization in Kotlin/Wasm
Companion objects now initialize in superclass-before-subclass order, matching JVM behavior. For most projects this is invisible. If you have companion objects in a class hierarchy that depend on a specific initialization sequence, test before you upgrade Kotlin/Wasm targets.
Gradle 9.7 and Build Tooling
Kotlin 2.4.20 is the first version to officially support Gradle 9.7.0, with compatibility tested across the full range from 7.6.3 to 9.7.0. Compiler diagnostic IDs are now surfaced through the Problems API, enabling IDEs and build tooling to group related errors more intelligently rather than surfacing raw compiler output.
Standard Library and Platform Updates
Four new collection functions land in the stdlib: allEqual(), allEqualBy(), allDistinct(), and allDistinctBy(). These cover validation patterns that previously required a toSet().size == 1 trick or a manual predicate loop.
val roles = listOf("admin", "admin", "admin")
roles.allEqual() // true
val users = listOf(User(1), User(2), User(3))
users.allDistinctBy { it.id } // true
StackTraceRecoverable is a new interface for custom exception classes, letting them integrate with kotlinx.coroutines stack trace recovery without adding a hard dependency on the coroutines library — useful for library authors who want to stay dependency-light.
Kotlin/Wasm picks up a 5–10% binary size reduction (lambdas now use shared base classes), Wasmtime runtime support in the Gradle plugin, and four new compilation modes ranging from monolith to multimodule-closed-world. The Kotlin Toolchain 0.12, released the same week, adds Compose Hot Reload from the command line and an MCP server for AI agent interaction with running applications.
Migration Checklist
- Update
kotlin = "2.4.20"in your version catalog orbuild.gradle.kts - Replace
kotlinwithkotlinrin all CI scripts, Dockerfiles, and shell scripts - Convert any
@JsFun("require(...)")to@JsModuleexternal declarations - For Kotlin/Native, add
kotlin.incremental.native=truetogradle.propertiesto enable beta incremental compilation - Test companion object initialization in Kotlin/Wasm class hierarchies before deploying upgraded targets
Full release notes are on the JetBrains blog and the complete changelog at kotlinlang.org.













