
Kotlin 2.4.0-RC landed on May 13. Context parameters — the feature that has been experimental since 2022 and moved to Beta in Kotlin 2.2.0 — are now Stable. If you have @OptIn(ExperimentalContextParameters::class) anywhere in your project, clean that up now. The stable release is scheduled for June or July, but the API is final as of this RC.
Context Parameters Are No Longer Experimental
There is one carve-out: context arguments (explicit context passing at the call site) and callable references with context parameters remain experimental. Everything else in the core context parameter syntax is Stable. The -Xcontext-parameters compiler flag is also gone — code guarded behind it compiles without it in 2.4.0-RC.
What Context Parameters Actually Do for Your Code
The classic problem: you have a logger, a transaction object, or a security context that needs to be accessible across an entire call chain. You can pass it explicitly to every function, or you can store it as a thread-local or property and manage the lifecycle yourself. Neither option is clean. Context parameters give you a third path: declare the dependency on the function, and it propagates implicitly through all callers that share the same context.
// Before: logger threaded manually through every call
fun processPayment(amount: Double, currency: String, logger: Logger) {
logger.info("Processing $amount $currency")
validateAmount(amount, logger)
recordTransaction(amount, currency, logger)
}
// After: logger declared as context, propagates implicitly
context(logger: Logger)
fun processPayment(amount: Double, currency: String) {
logger.info("Processing $amount $currency")
validateAmount(amount)
recordTransaction(amount, currency)
}
The context propagates implicitly through each called function that also declares context(logger: Logger). If your codebase threads the same service or context object through ten layers of function calls, this is the refactor you have been waiting for.
One thing to check during migration: if you have overloads that differ only by their context parameter, the compiler may flag ambiguity at call sites. You resolve this with explicit context arguments — new in this RC. The context parameters documentation covers the disambiguation syntax.
Swift Packages Are Now First-Class KMP Dependencies
KMP developers targeting iOS have been stuck with CocoaPods as the mechanism for consuming Swift and Objective-C libraries. CocoaPods requires Ruby, a Gemfile, pod install on every machine, and Xcode workspace manipulation. It is a dependency on a dependency, and it has generated CI failures on every team that has touched it.
Kotlin 2.4 changes this. Using the swiftPMDependencies block in your Gradle config, you can declare Swift Package Manager dependencies directly. SPM is built into Xcode and requires no additional tooling.
// build.gradle.kts — declare Swift packages as KMP dependencies
swiftPMDependencies {
remotePackage("https://github.com/apple/swift-argument-parser", from = "1.3.0") {
products("ArgumentParser")
}
}
Local packages are supported too. First setup requires running a Gradle task to link the generated package with your Xcode project, but after that the workflow is standard SPM. JetBrains has published a CocoaPods to SPM migration guide. If you are starting a new KMP project today, use SPM from the start. This feature ships with the 2.4.0-Beta2 version of the KMP Gradle plugin.
The same release also adds support for exporting kotlinx.coroutines Flows directly to Swift. iOS-side consumers can now work with Kotlin Flows without wrapper code, reducing the surface area of the Kotlin-Swift bridge considerably.
Kotlin/Wasm: Incremental Builds Are Default, Component Model Arrives
Two updates for Kotlin/Wasm in 2.4.0-RC. First, incremental compilation is now Stable and enabled by default — introduced experimentally in Kotlin 2.1.0, if you have been disabling it out of caution, that caution is no longer warranted. Wasm builds will rebuild only the files affected by recent changes.
Second, experimental support for the WebAssembly Component Model arrives. The Component Model defines a standard interface format that lets Wasm modules from different languages interoperate — a Kotlin/Wasm component can expose and consume interfaces that a Rust or Python Wasm module also understands. This is early-stage, but it is the foundation for cross-language Wasm workloads on the server. If you are evaluating Kotlin for server-side Wasm targets, this is the feature to watch.
JVM and Standard Library: Three Quick Updates
- UUID is Stable.
kotlin.uuid.Uuidin the common standard library has graduated. Remove@OptIn(ExperimentalUuidApi::class). Cross-platform UUID generation works across JVM, Android, native, and Wasm targets without a third-party library. - Java 26 support. The Kotlin compiler can now generate Java 26 bytecode. Update your JVM target if your project is moving to Java 26.
- Maven gets automatic JVM target alignment. The Kotlin Maven plugin now auto-aligns the JVM target with your Java compiler version when
<extensions>is enabled. The persistent mismatched-target warning from mixed Java/Kotlin Maven projects goes away without any manual configuration.
How to Try the RC Now
// build.gradle.kts
plugins {
kotlin("jvm") version "2.4.0-RC"
// or for multiplatform:
// kotlin("multiplatform") version "2.4.0-RC"
}
The RC is compatible with Gradle 7.6.3 through 9.5.0. The official 2.4.0-RC release notes cover every change in detail. Stable is expected in June or July.
Context parameters going stable is worth treating as more than a housekeeping task. Frameworks will start using them in public APIs once stable ships. Developers who know how to use them will read those APIs without friction. The ones who skipped this release will spend time catching up later in the year.













