Swift Export compatibility and migration
May 11, 2026 ยท View on GitHub
Starting with Kotlin 2.2.20 you can use the (experimental) Swift export, which provides direct Kotlin - Swift interoperability.
Warning
Swift export is still experimental and actively being developed! It doesn't yet support all language features, might still contain bugs, and its behaviour could change in future versions. It is NOT recommended to use Swift export in production just yet!
Once Swift export is complete and stable it'll likely completely remove the need for KMP-NativeCoroutines.
So to support you in your journey to Swift export:
- KMP-NativeCoroutines will try to be "compatible" with Swift export as much as possible, allowing you to start testing with Swift export as soon as possible.
- A migration path will be provided once coroutines support in Swift export becomes stable.
Known limitations
These are the known limitations with Swift export and KMP-NativeCoroutines.
๐จ NativeSuspend and NativeFlow are unsupported
At the moment Swift export has some issues with functional return types and generics.
Unfortunately KMP-NativeCoroutines heavily relies on functional return types, making it incompatible with Swift Export. For now the plugin just clones your original functions and properties to prevent your Kotlin builds from failing.
Enabling Swift export
To enable Swift export with KMP-NativeCoroutines you'll need to activate the Swift export compatibility mode:
// build.gradle.kts
nativeCoroutines {
swiftExport = true
}
Usage
Only some coroutines related code can be used when Swift export is enabled.
Note
You can also use the generated properties for the StateFlow.value and SharedFlow.replayCache values.
Suspend functions
You can use suspend functions as async functions in Swift without any changes:
let letters = try await asyncFunction(for: randomLettersGenerator.getRandomLetters(throwException: throwException))
Note
It's recommended to keep using the asyncFunction(for:) function for now.
However this function is a no-op and can eventually be removed.
For Combine and RxSwift there are helper functions available, e.g.:
- let future = createFuture(for: randomLettersGenerator.getRandomLetters(throwException: throwException))
+ let future = createFuture(for: { await self.randomLettersGenerator.getRandomLetters(throwException: throwException) })
Flows
You can use Flows as AsyncSequences without any changes:
let sequence = asyncSequence(for: clock.time)
Note
Upon cancellation Swift export will throw a CancellationError instead of ending the iteration by returning nil.
Note
It's recommended to keep using the asyncSequence(for:) function for now.
However this function is a no-op and can eventually be replaces with a call to asAsyncSequence().
For Combine and RxSwift there are helper functions available, e.g.:
- let publisher = createPublisher(for: clock.time)
+ let publisher = createPublisher(for: asyncSequence(for: clock.time))