NewsDeveloper ToolsProgramming Languages

Kotlin 2.4: Swift Export Alpha, K1 Compiler Removed

Kotlin 2.4.0 release showing Swift export and K1 compiler removal
Kotlin 2.4 ships Swift export in Alpha and removes the K1 compiler frontend

Kotlin 2.4.0 shipped in June and the thing that demands immediate attention is a removal: the K1 compiler is gone. If your build sets languageVersion = "1.9" anywhere — a Gradle convention plugin, a third-party build tool, a legacy module — it will not compile on 2.4. There is no fallback. Beyond that hard stop, the release delivers the Swift export that Kotlin Multiplatform developers have been asking for, a cleaner solution to a boilerplate pattern every Android developer knows, and an experimental bracket syntax that will generate the usual debates.

What Breaks in 2.4

The K1 compiler frontend is gone. Since Kotlin 2.0, K2 has been the default, but projects could still force the old frontend by setting -language-version 1.9. That escape hatch is closed in 2.4. The compiler’s LanguageVersionSettings now sets FIRST_SUPPORTED = KOTLIN_2_0 — anything below that is rejected outright.

If you are upgrading, search every build file for languageVersion = "1.9" before you do anything else. The most common sources are legacy Spring Boot 2.x projects, Gradle convention plugins with hardcoded language versions, and KSP configurations that never got updated. Remove the pin, let K2 take over, and address any type errors K2’s stricter resolution uncovers. JetBrains telemetry puts the affected share at around 2% of active projects — a small number, but if you are in it, you cannot skip this step.

Three other breaking changes require attention. Kotlin/Native raises Apple deployment targets: iOS and tvOS move from 14.0 to 15.0, macOS from 11.0 to 12.0, watchOS from 7.0 to 8.0. Projects targeting iOS 14 need to raise their minimum or stay on Kotlin 2.3.x. Additionally, the Compose compiler feature flags StrongSkipping and IntrinsicRemember are now compile errors — if those appear in your compiler options, the build will fail. Maven users also lose KotlinScriptMojo; the replacement is standalone .kts scripts.

Swift Export Enters Alpha

For Kotlin Multiplatform developers targeting iOS, 2.4’s headline feature is Swift export advancing from Experimental to Alpha. That status change matters in practice: Experimental meant “this may completely change”; Alpha means “it is stable enough to build on, but expect some breaking changes between releases.” It is the first point where evaluating Swift export in a real project makes sense.

Swift export generates Swift bindings for public Kotlin declarations without going through Objective-C headers. Previously, every Kotlin function that crossed into Swift arrived wrapped in ObjC bridging code — SharedKt.functionName() calls, KotlinInt wrappers, nullable boxing. With Swift export, Kotlin’s suspend functions map to Swift async/await and Flow becomes AsyncSequence:

// Kotlin shared module
suspend fun fetchUser(id: String): User = ...
fun userUpdates(): Flow<User> = ...
// Swift — no Objective-C intermediary
let user = try await fetchUser(id: "42")
for try await update in userUpdates().asAsyncSequence() {
    render(update)
}

To enable it, add a swiftExport { } block to your build.gradle.kts and update the Xcode Run Script build phase to call ./gradlew :shared:embedSwiftExportForXcode instead of the old Kotlin framework script. The full setup is documented in the Swift export documentation.

There are real limitations at Alpha. Swift export only works with direct Xcode integration — CocoaPods projects cannot use it yet. Generic type parameters are erased to their upper bounds, and you cannot subclass Kotlin classes in Swift. However, suspending functions, overloads, and nullability without boxing all work. For most shared business logic, that is enough to start evaluating.

The Rest of 2.4 Worth Knowing

Explicit backing fields are now stable, and if you write Android code, this removes a pattern you have written hundreds of times. The standard approach for exposing a MutableStateFlow as a read-only StateFlow requires two declarations and a conversion call. With 2.4’s explicit backing fields, one declaration handles it:

// Before
private val _state = MutableStateFlow(UiState())
val state: StateFlow<UiState> = _state.asStateFlow()

// After — one declaration, compiler enforces visibility
val state: StateFlow<UiState>
    field = MutableStateFlow(UiState())

The public type is StateFlow; the backing field holds the MutableStateFlow. The compiler enforces that the field type’s visibility cannot exceed the property’s, so the mutable reference stays internal to the class.

Context parameters, which became stable earlier in the 2.4 release cycle, are now available without any opt-in flag — no annotation needed to thread loggers, database connections, or auth sessions through a call graph. Note that naming the context argument at the call site remains experimental behind -Xexplicit-context-arguments; full support lands in 2.5.

Collection literals arrived as an experimental feature behind the -Xcollection-literals compiler flag. The syntax is val xs: List<Int> = [1, 2, 3], which desugars to List.of() calls. Do not enable this in production — the semantics for custom types using the of operator are still being finalized. It is worth watching for 2.5 or 2.6.

On the runtime side, the Concurrent Mark-and-Sweep garbage collector is now the default for Kotlin/Native, delivering roughly 50% memory savings with no code changes required. Kotlin/Wasm adds experimental WebAssembly Component Model support, enabling cross-language WASM interoperability for serverless and edge use cases where Kotlin modules need to compose with components written in other languages.

What to Do Now

If you are upgrading from 2.3.x: audit every build file for languageVersion = "1.9" before touching anything else. Check convention plugin modules, Gradle included builds, and any third-party plugin configurations that set the language version implicitly. Raise Apple deployment targets if you ship iOS apps. Remove the deprecated Compose compiler feature flags. Then upgrade and run a full build before exploring new features.

If you are already on K2 and upgrading from an earlier 2.x release: the Kotlin 2.4 compatibility guide is the place to start. The breaking surface is smaller for projects that already made the K2 transition. After that, the official 2.4.0 release notes walk through every change with code examples. Swift export and explicit backing fields are the two features worth testing on a branch before rolling to production.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News