Kotlin Help

What's new in Kotlin 2.4.0-Beta1

Released: March 31, 2026

The Kotlin 2.4.0-Beta1 release is out! Here are some details of this EAP release:

Update to Kotlin 2.4.0-Beta1

The latest version of Kotlin is included in the latest versions of IntelliJ IDEA and Android Studio.

To update to the new Kotlin version, make sure your IDE is updated to the latest version and change the Kotlin version to 2.4.0-Beta1 in your build scripts.

New features

In previous Kotlin releases, several new features were introduced as Experimental. The following features have now graduated to Stable in Kotlin 2.4.0-Beta1, so you no longer need to opt in to use them:

New features

Language

Kotlin 2.4.0-Beta1 promotes context parameters and annotation use-site targets features to Stable. This release also introduces explicit context arguments for context parameters.

Stable features: Context parameters and features for annotation use-site targets

Kotlin 2.2.0 introduced a few language features as Experimental. We're happy to announce that the following language features are now Stable in this release:

See the full list of Kotlin language design features and proposals.

Explicit context arguments for context parameters

Kotlin 2.4.0-Beta1 introduces explicit context arguments for context parameters.

Kotlin 2.3.20 changed the overload resolution for context parameters. As a result, calls to overloads that differ only by context parameters can become ambiguous.

You can now resolve this ambiguity by passing an explicit context argument at the call site.

Here's an example:

class EmailSender class SmsSender context(emailSender: EmailSender) fun sendNotification() { println("Sent email notification") } context(smsSender: SmsSender) fun sendNotification() { println("Sent SMS notification") } context(defaultEmailSender: EmailSender, defaultSmsSender: SmsSender) fun notifyUser() { // Selects the overload with the EmailSender context parameter sendNotification(emailSender = defaultEmailSender) // Selects the overload with the SmsSender context parameter sendNotification(smsSender = defaultSmsSender) }

You can also use explicit context arguments instead of the context() function to reduce nesting and make some calls easier to read. If you need to use the same context arguments in multiple calls, use the context() function instead.

This feature is Experimental. To opt in, add the following compiler option to your build file:

kotlin { compilerOptions { freeCompilerArgs.add("-Xexplicit-context-arguments") } }
<build> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <configuration> <args> <arg>-Xexplicit-context-arguments</arg> </args> </configuration> </plugin> </plugins> </build>

For more information, see the feature's KEEP.

Standard library

Kotlin 2.4.0-Beta1 adds new extension functions for converting unsigned integers to BigInteger on the JVM. It also adds support for checking sorted order in iterables, arrays, and sequences.

New API for converting unsigned integers to BigInteger on the JVM

Kotlin 2.4.0-Beta1 introduces the UInt.toBigInteger() and ULong.toBigInteger() extension functions on the JVM.

Previously, converting UInt and ULong values to BigInteger required string-based workarounds or custom conversion logic. Starting with Kotlin 2.4.0-Beta1, you can now use .toBigInteger() to convert unsigned integer values directly to BigInteger.

Here's an example:

fun main() { val unsignedLong = Long.MAX_VALUE.toULong() + 1uL val unsignedInt = UInt.MAX_VALUE println(unsignedLong.toBigInteger()) // 9223372036854775808 println(unsignedInt.toBigInteger()) // 4294967295 }

We would appreciate your feedback in YouTrack.

Support for checking sorted order

Kotlin 2.4.0-Beta1 adds new extension functions for checking sorted order in iterables, arrays, and sequences.

This includes the following extension functions:

  • .isSorted()

  • .isSortedDescending()

  • .isSortedWith(comparator)

  • .isSortedBy(selector)

  • .isSortedByDescending(selector)

You can use these extension functions to check whether elements are already sorted without sorting them again or creating your own helper functions. They return true if the elements are in the specified order, or if there are fewer than two elements, and false otherwise. These functions stop as soon as they encounter an out-of-order pair, which makes them efficient for large inputs.

Here's an example of checking sorted order with .isSorted() and .isSortedBy() functions:

data class User(val name: String, val age: Int) fun main() { val numbers = listOf(1, 2, 3, 4) println(numbers.isSorted()) // true val users = listOf( User("Alice", 24), User("Bob", 31), User("Charlie", 29), ) println(users.isSortedBy(User::age)) // false }

We would appreciate your feedback in YouTrack.

Kotlin/JVM

Kotlin 2.4.0-Beta1 supports a new Java version and enables annotations in metadata by default.

Support for Java 26

Starting with Kotlin 2.4.0-Beta1, the compiler can generate classes containing Java 26 bytecode.

Annotations in metadata enabled by default

The Kotlin Metadata JVM library in Kotlin 2.2.0 introduced support for reading annotations stored in Kotlin metadata. With this support, the Kotlin compiler writes annotations into metadata alongside the JVM bytecode, making them accessible to the Kotlin Metadata JVM library. As a result, annotation processors and other tools can understand and manipulate these annotations at the metadata level without using reflection or modifying source code.

In Kotlin 2.4.0-Beta1, this support is enabled by default.

Kotlin/Native

Kotlin 2.4.0-Beta1 brings support for Swift package import.

Swift package import

Kotlin Multiplatform projects now can declare Swift packages as dependencies for an iOS app in their Gradle configuration:

// build.gradle.kts kotlin { swiftPMDependencies { swiftPackage( url = url("https://github.com/firebase/firebase-ios-sdk.git"), version = from("12.11.0"), products = listOf( product("FirebaseAI"), product("FirebaseAnalytics"), ... }

For working samples and more detailed information, see SwiftPM import.

If your project relies on CocoaPods dependencies, you can migrate the current setup to use Swift packages. The KMP tooling accounts for this use case and helps you reconfigure the project automatically. For details, see our CocoaPods migration guide.

Kotlin compiler

Kotlin 2.4.0-Beta1 includes more consistent behavior for inline functions declared in the same module during .klib compilation.

Consistent intra-module function inlining during klib compilation

Previously, function inlining behaved inconsistently on different Kotlin platforms. The JetBrains team is working to unify it across all supported platforms to ensure the same compatibility guarantees.

On the Kotlin/JVM, function inlining happens at compile time. So, when Kotlin sources are compiled with the Kotlin/JVM compiler, the resulting class files have no inline function calls in the bytecode because the bodies of inline functions are inlined into their call sites, so their behavior is fixed during compilation.

On the contrary, on Kotlin/Native, Kotlin/JS, and Kotlin/Wasm, function inlining did not happen during source-to-klib compilation, only during binary generation. As a result, the behavior of inline functions wasn't fixed during .klib compilation, and .klib libraries didn't provide the same compatibility guarantees for inline functions as Kotlin/JVM does.

Kotlin 2.4.0-Beta1 takes the first step in unifying the behavior of inline functions by enabling intra-module inlining when generating .klib artifacts:

// Existing logging.klib library inline fun logDebug(message: String) { println("[DEBUG] $message") }
// Currently compiled App module inline fun greetUser(name: String) { println("Hello, $name!") } fun main() { logDebug("App started") // Not inlined: declared in another module greetUser("Alice") // Inlined: declared in the same module }

When compiled to a .klib, the code looks something like:

// Pseudocode fun main() { logDebug("App started") // Not inlined, declared in another module val tmp0 = "Alice" println("Hello, $tmp0!") // Inlined from greetUser() }

This means only inline functions declared in the same module are inlined during .klib compilation. Other functions, in this case, are inlined during the generation of platform-specific binaries.

How to enable

Starting with 2.4.0-Beta1, the intra-module inlining is enabled by default for Kotlin/Native, Kotlin/JS, and Kotlin/Wasm.

If you face unexpected problems with this feature, you can disable it using the following compiler option in the command line:

-Xklib-ir-inliner=disabled

The next step is to enable cross-module inlining to ensure all inline functions in the project are consistently inlined. This change is planned for future Kotlin releases, but you can already try it out using the following compiler option in the command line:

-Xklib-ir-inliner=full

Please share your feedback and report any problems in YouTrack.

31 March 2026