How do Duet and Compose Multiplatform differ?
org.jetbrains.compose artifacts exist for the non-Android targets Duet does not render on.
What does Compose Multiplatform’s iOS rendering actually do?
Compose Multiplatform has been stable on iOS since 1.8 (May 2025); current is 1.12.0 (August 2026). On iOS the framework draws components onto a canvas via Skia — the same rendering-ownership decision Flutter makes, but without a language runtime: the Kotlin is compiled by Kotlin/Native, so the quadrant cell is “framework draws, compiled logic.” Two qualifiers keep this description current:- Text input is going hybrid. Since 1.11.0 an experimental text field is backed by a real native
UIView, giving platform-native gestures, selection handles and context menus inside the canvas. - Accessibility is bridged to the native services. Compose semantics are mapped to native iOS Accessibility Services — VoiceOver and Full Keyboard Access work, and
testTagsurfaces asaccessibilityIdentifierfor XCTest audits. The documented shape is re-implementation plus mapping: the framework maintains the bridge, and platform behaviors arrive through it rather than by default. A fully native interface inherits new OS accessibility features on the OS’s schedule.
ComposeUIViewController embeds Compose screens in SwiftUI apps, and UIKitViewController embeds native views inside Compose — so mixed adoptions are a documented path. JetBrains’ integration guide names maps, camera and web views as the cases for a native view inside Compose, and the same interop is the customization path: the catalog is Material 3 on every platform, so a control that must look and behave like UIKit’s own is a native view embedded through the interop — built in Kotlin through Kotlin/Native’s Objective-C interop, or in Swift when the API is Swift-only — and anything outside the canvas — a home-screen widget, a share extension — is Swift regardless. The fit is UI-neutral business applications whose screens are the same everywhere; the more the iOS interface must differ from the Android one, the more of it is written natively with the framework in between.
If the language is the same, what is the actual choice?
Fidelity versus coverage, and what “agree” means:- Compose Multiplatform maximizes shared code: interface included, one implementation, agreement by construction. The iOS interface is Compose — Material by default, themable toward Cupertino idiom, but authored in the shared dialect and rendered by the framework.
- Duet fixes the interface as each platform’s own and narrows sharing to what a fixture can check: state, actions, effects and their ordering. The iOS app is SwiftUI a platform engineer (or Apple’s own tooling) recognizes without caveats; the price is a second view layer, written per feature. Agreement is by verification — recorded fixtures replayed on both platforms, byte-compared in CI.
What if one screen must be native and fast?
On Android nothing changes: Compose Multiplatform is Jetpack Compose there, and a camera preview, aSurfaceView or a vendor SDK view is the same AndroidView interop a Duet Android app would use. On iOS, drawing-heavy screens stay shared — Compose’s Canvas renders through Skia in Kotlin — while an island that must be UIKit’s own (the docs’ own examples: MKMapView, a camera, WKWebView) is a UIKitView whose factory returns the native view, hosted inside a Skia-drawn screen. Capture and processing pipelines — AVFoundation on iOS, CameraX and MediaCodec on Android — are platform code behind expect/actual declarations or a Swift wrapper the Kotlin calls into.
The drawbacks: the iOS island is UIKit code inside a framework-rendered screen, so that screen has two renderers and two ownership models, and the pipeline’s logic sits outside the shared implementation, kept equal by review. On Android there is no drawback relative to Duet, because the toolkit is the same.
Do you write and compile native code for it? On Android, no new language: the island is Kotlin in the same Gradle build. On iOS, usually not Swift either. Kotlin/Native’s Objective-C interop lets Kotlin construct UIKit objects directly — the docs’ own factory builds MKMapView() in Kotlin — and Xcode compiles the app target around the framework Kotlin/Native produces. Swift becomes necessary for Swift-only APIs, because “pure Swift modules are not yet supported” by the interop: a SwiftUI view such as Map, or a Swift-only vendor SDK, is written in Swift, exposed to Objective-C, and compiled by Xcode.
Can the island be SwiftUI or Compose? Compose is the interface on Android already. On iOS a SwiftUI view is the documented case of the Swift exception above: the SwiftUI integration guide wraps it in UIHostingController, hands the controller to UIKitViewController, and states that “you have to write them in Swift and pass them to a Kotlin function”. The reverse direction, ComposeUIViewController inside a SwiftUI app, is documented on the same page.
In a Duet app the island is ordinary platform code — AVFoundation and Metal in the SwiftUI app, CameraX and MediaCodec in the Compose app — with nothing between it and the OS. The reducer decides when capture starts, which filter applies and what happens with the result; a worker runs the pipeline. What is recorded and byte-compared is that seam: the requests the reducer makes and the results that come back. The pipeline’s internals are outside the verified surface, and the island is written twice, once per platform: Swift compiled by Xcode, Kotlin compiled by Gradle, by design.
What does Compose Multiplatform do better?
- More shared code. The interface is written once. Duet writes it twice by design.
- The iteration loop. Compose Hot Reload is stable and on by default since 1.10.0 (January 2026); 1.12.0 added an experimental MCP server so AI agents can drive reloads, take screenshots and inspect the semantic tree.
- Reach beyond the two phone platforms. Desktop is stable and the web target is in beta from the same codebase; Duet targets iOS and Android only.
- One design system by default. If the product wants the same branded look everywhere, sharing the interface is the shorter path to it.
When should you pick which?
Pick Compose Multiplatform for UI-neutral business applications — forms, lists, dashboards — when your team is Kotlin-first, a single branded interface across platforms (and possibly desktop and web) is a feature, and platform-idiomatic iOS is a nice-to-have rather than a requirement. Pick Duet when SwiftUI-native iOS is a requirement, when you want no cross-platform UI dependency in the iOS app, or when the domain needs behavior agreement to be a mechanical check — the recorded corpus is what turns “the apps agree” from a review judgment into a failing build. The two stacks also compose over time in one direction: because Duet’s core is ordinary Kotlin Multiplatform, its skills, libraries and tooling transfer — kotlinx, Ktor, the current stable Kotlin (2.4.10, which is what the Duet scaffold emits). Kotlin’s Swift Export, in alpha since Kotlin 2.4.0, is the platform’s stated direction for the Swift-facing seam both stacks consume today through the Objective-C bridge.Common questions
Is Duet built on Compose Multiplatform?
Is Duet built on Compose Multiplatform?
No. Duet’s shared core is plain Kotlin Multiplatform — logic only, no UI framework in
commonMain. Android renders with Jetpack Compose (androidx artifacts), iOS with SwiftUI. Compose Multiplatform is JetBrains’ extension of Jetpack Compose to non-Android targets, and a Duet project has no dependency on it.Can I mix the two — Compose Multiplatform screens inside a Duet app?
Can I mix the two — Compose Multiplatform screens inside a Duet app?
Technically the interop exists (a Compose screen is embeddable in SwiftUI via ComposeUIViewController), but a Duet project’s parity contract covers logic, and its iOS interface convention is SwiftUI. Mixing rendering models per screen re-creates the consistency problem the architecture is built to remove — if shared UI is what you want, Compose Multiplatform proper is the honest choice.
What about Kotlin/Native performance and the GC on iOS?
What about Kotlin/Native performance and the GC on iOS?
Both stacks stand on the same runtime facts: Kotlin/Native compiles to machine code and manages memory with a concurrent mark-and-sweep collector over a shared heap — a small runtime, no VM or interpreter. Whatever holds for one stack’s iOS core holds for the other’s; it is not a differentiator between them.
Which does Google support?
Which does Google support?
Google officially supports Kotlin Multiplatform for sharing business logic between Android and iOS, and ships KMP artifacts for Room, DataStore, ViewModel and more — that support statement covers the shared-core layer both stacks use. Compose Multiplatform itself is developed by JetBrains, extending Google’s Jetpack Compose beyond Android.
Duet projects are scaffolded by Modaal — starting a Duet project walks through the two template cards.
Sources and further reading
- Compose Multiplatform and Jetpack Compose — what the framework is relative to androidx Compose
- Compose Multiplatform 1.8, 1.10 and 1.12 release posts — iOS stable, Hot Reload, the MCP server
- iOS accessibility in Compose Multiplatform — the semantics-to-native mapping and its documented gaps
- Kotlin Multiplatform on developer.android.com — Google’s support statement and KMP Jetpack artifacts
- Kotlin releases — current stable and the Swift Export status
- Integration with the UIKit framework, Integration with the SwiftUI framework and Using Views in Compose — the escape-to-native routes for a heavy screen on each platform
- Interoperability with Swift/Objective-C — what Kotlin can call on iOS without Swift, and the Swift-only limit
- The Duet framework on GitHub — both flavors, the recording toolchain and the versioned contracts
Read next
The best cross-platform frameworks in 2026
The full survey — where the share-the-UI and share-the-logic cells sit on the quadrant.
Handling platform-specific UI
How Duet keeps two native interfaces honest: the presentation contract and recorded divergence.
Should you share code between iOS and Android?
The decision one level up: write twice, share everything, or share the logic.
How to build testable Android apps
The recorded-scenario discipline that gives Duet its verification story, shown in code.