How should you compare cross-platform frameworks?
Who draws the screen × where the feature logic runs. React Native and Compose Multiplatform occupy the two mixed cells — a single native-vs-cross-platform line cannot place either.
How do the frameworks compare?
Which approaches escape to native for a heavy screen?
The island row splits the table three ways. Native already — Duet, two native apps, the KMP shared-core practice, and Skip on iOS: a Metal view, a camera pipeline or a video editor is ordinary platform code with no bridge, written per platform. Escape through the framework’s bridge — Flutter (aTexture or a platform view, which the docs say “come with performance trade-offs”), React Native (a Fabric Native Component plus a Native Module), Compose Multiplatform on iOS (a UIKitView built in Kotlin through Objective-C interop, or in Swift for Swift-only APIs), .NET MAUI (a handler reaching the PlatformView), Ionic/Capacitor (a plugin whose native UI lives in its own view controller beside the web view): the island is written per platform anyway, plus the bridge that carries its parameters and results, and its logic leaves the shared implementation. Drawn by the framework — Flutter and Compose Multiplatform keep a drawing-heavy screen shared when it needs no platform API: GLSL shaders and painters in Dart, Canvas on Skia in Kotlin. The pairwise pages give each escape’s mechanics; Duet’s side is the same on all three: the reducer decides, a worker runs the pipeline, and the recorded seam is what CI compares.
Whether the island means writing and compiling native code, per framework: Flutter, React Native and Ionic/Capacitor — yes, in Swift or Objective-C(++) and Kotlin or Java, compiled by Xcode and Gradle in the app build, unless an existing plugin or library covers the island, which spares the writing and not the compiling. Compose Multiplatform — usually Kotlin only, because Kotlin/Native’s Objective-C interop builds UIKit views from Kotlin, with Swift reserved for Swift-only APIs. .NET MAUI — platform-specific C# against the platform bindings, compiled by .NET per platform; no Swift or Kotlin. Skip — Swift on iOS as usual, and on Android either Kotlin or Swift in #if SKIP blocks that transpile to Kotlin. KMP shared-core stacks, two native apps and Duet — yes, by design: Swift compiled by Xcode, Kotlin compiled by Gradle.
Whether the island can be SwiftUI or Jetpack Compose rather than UIKit and Android Views: for Duet, two native apps, KMP shared-core stacks and Skip they are the interface already. Flutter and React Native get them wrapped — a SwiftUI view through UIHostingController, Compose through ComposeView — inside a platform view or a Fabric Native Component; React Native’s own guides mention Swift nowhere, while Expo, the framework its documentation recommends, adds Swift and Kotlin modules and Expo UI, “a set of components that allow you to build UIs directly with Jetpack Compose and SwiftUI from React”. Compose Multiplatform is Compose on Android and takes SwiftUI on iOS through UIHostingController passed to UIKitViewController, written in Swift. Ionic/Capacitor gets them only as a native screen a plugin presents outside the web view. .NET MAUI’s handler surface is UIKit and Android Views through the .NET bindings.
Is the shared-core shape new?
No. The bottom-left cell — platform draws, compiled shared core — is established practice under several names. Kotlin Multiplatform shared-logic practice is officially supported by Google and carries the mainstream case studies: Forbes (80%+ shared logic), McDonald’s, Cash App (moved from shared JavaScript to KMP starting 2018), Google Docs on iOS, and 9GAG — which chose KMP after trying Flutter and React Native. The same shape exists with a Rust core: Crux captures effects as values executed by native shells — the same effects-as-data idea Duet uses — and Mozilla’s UniFFI and Signal’s libsignal ship Rust cores under native apps at scale. One detail in JetBrains’ own materials is worth reading as data: its shared-logic case-study list is long and mainstream, while its shared-UI list is short and recent — shared logic under native UI is the mainstream KMP shape. What lacks close prior art is the verification layer: a recorded behavior corpus that both platforms replay, byte-compared in CI, as the gate for parity. The KMP and Rust stacks above share code and share tests; none of them ships a mechanism whose job is to fail the build when the two apps’ behavior diverges. That layer — not the shared core — is Duet’s contribution, and it is why the table gives Duet a different “what proves agreement” cell than the stacks it otherwise resembles.What does the table not score?
App size. Shipped runtimes have documented weight: Flutter’s own FAQ measured a minimal release APK at ~4.3 MB (ARM32) / 4.8 MB (ARM64) and a minimal IPA download at ~10.9 MB — figures the FAQ dates to March 2021. Duet’s compiled core measured +3 MB on the Android app of the shipped product Modaal’s pages quote. React Native and Compose Multiplatform publish no equivalent official minimal-app figures, so this page quotes none. OS-release-day behavior. A native interface inherits a new OS version’s controls, behaviors and accessibility features on the OS’s schedule. A framework-drawn interface adopts them when the framework does — Compose Multiplatform’s FAQ presents the same fact from the other side, noting a canvas-drawn UI “will stay the same” across OS updates. Both readings are true: consistency for the canvas, currency for the native toolkit. Accessibility follows the same line — CMP maps its semantics to native iOS Accessibility Services (VoiceOver and Full Keyboard Access work; the mapping is maintained by the framework), while native toolkits get new platform accessibility features without a bridge. Hiring and team shape. The runtime rows map to talent pools: JavaScript/TypeScript (React Native, Ionic) is the largest; Dart expertise is mostly Flutter expertise; Kotlin rows draw from the Android population; Skip and Duet’s iOS half draw from the Swift population. No numbers here age well enough to print — match the row to the team you can actually staff. The iteration loop. Hot reload is a real productivity difference: mature in Flutter (stable on the web target since 3.35), stable and default in Compose Multiplatform since 1.10.0. Compiled-core stacks, Duet included, iterate with per-platform previews and fast logic tests instead.Who owns each framework in 2026?
Ownership moved enough in the last two years that most comparison pages are out of date:- React Native is governed by the React Foundation under the Linux Foundation (February 2026), with Amazon, Meta, Microsoft, Expo, Callstack and others as founding members. “Meta’s framework” is no longer the governance story.
- Flutter remains Google-led, with Canonical named lead maintainer of Flutter Desktop (May 2026) — stewardship is widening rather than narrowing.
- Compose Multiplatform is JetBrains’, extending Google’s Jetpack Compose; the two companies co-anchor the Kotlin ecosystem.
- Ionic has operated under OutSystems since November 2022; Ionic 9 (August 2026) carries support commitments into 2027.
- .NET MAUI is Microsoft’s, on .NET’s LTS cadence (MAUI 10, November 2025). The precedent worth knowing when weighing any vendor framework: Xamarin support ended May 1, 2024, and its apps required migration.
- Skip became free and open source (MPL-2.0) in January 2026 and releases actively.
- Duet is Modaal’s, open on GitHub with versioned contracts, in open beta.
What do the usage surveys say?
Quote surveys with their year, because the traps are real. Stack Overflow’s 2024 survey — the last edition with a cross-platform category — put Flutter at 9.4% and React Native at 8.4% of all respondents; the 2025 survey dropped the category, so any page citing a 2025 Stack Overflow cross-platform figure is miscited. JetBrains reports Kotlin Multiplatform usage among its developer-ecosystem respondents doubling from 7% (2024) to 18% (2025). The widely re-cited Statista cross-platform chart’s latest data year is 2023 (Flutter 46%, React Native 35% of cross-platform developers) — current pages re-cite it as if fresh; it is not.How do AI coding agents change the choice?
Two properties matter, and they pull in different directions. Fluency: an agent has seen more JavaScript, React and Flutter than anything else, and one-language codebases are easy for it to move through. Verifiability: an agent compounds its own mistakes unless the project gives it mechanical gates, and this is where the frameworks now differ visibly. Compose Multiplatform 1.12.0 ships an experimental MCP server that lets an agent drive hot reloads, screenshot the app and inspect the semantic tree — agent-operable UI tooling. Duet’s recorded corpus is agent-checkable behavior gating: a screen cannot wire to logic without a passing recording, and every push replays the corpus on both platforms — the argument in full is on the testable-apps page. The iOS architecture comparison scores the same axis across architectures rather than frameworks.Which should you pick?
- Interface-heavy, brand-driven product; one team end to end: Flutter — or Compose Multiplatform if the team is Kotlin-first.
- Web engineering team; modest native-module needs: React Native (start with Expo, per the project’s own recommendation) — or Ionic if the product is close to a web app already.
- An existing web app to repackage: Ionic/Capacitor.
- A .NET organization: MAUI, with eyes open about the Xamarin precedent and the LTS calendar.
- A Swift team that wants Android from its existing SwiftUI source: Skip.
- A Kotlin team that wants full control of its stack: KMP with Decompose or MVIKotlin — you assemble the architecture and the test strategy yourself.
- A rules-dense product that needs native UI on both platforms and provable behavior parity: Duet — the pairwise pages (vs Flutter, vs React Native, vs Compose Multiplatform) argue each match-up in full.
- Two independent platform teams, by organizational design: two native codebases, with manual QA priced in as the parity mechanism.
Common questions
Which cross-platform framework has the best performance?
Which cross-platform framework has the best performance?
This page prints no benchmark verdicts: the rendering models differ enough that microbenchmarks mislead, and the ranking pages that score “performance” cite each other rather than measurements. The structural facts that do hold: compiled rows carry no interpreter between your logic and the CPU; canvas renderers control their own frame pipeline; web views are bound by the browser engine. Measure your own workload if performance is the deciding axis.
Is cross-platform cheaper than native?
Is cross-platform cheaper than native?
At launch, a single implementation is cheaper than two — that is arithmetic. Total cost depends on what the product needs later: per-platform code behind channels and modules, interface rework to fit platform expectations, and the QA budget for whatever the framework’s parity answer is. The share-code page walks the cost side, including the measured ~40% dual-platform change premium in Duet’s model — against a 100% baseline of doing everything twice.
Why isn't Xamarin in the table?
Why isn't Xamarin in the table?
Xamarin’s support ended May 1, 2024; .NET MAUI is its successor and holds the table column. Xamarin remains relevant only as the migration precedent quoted in the governance section.
What about PWAs — skipping the stores entirely?
What about PWAs — skipping the stores entirely?
A progressive web app is a real option for content-driven products and dodges this page’s question entirely — no second codebase, no framework row. The trade is capability and distribution: store presence, platform APIs, background behavior and platform-native interface expectations. Teams that need those come back to this table; teams that do not can stop at the web.
Every list ranks Flutter and React Native first. Why doesn't this one rank at all?
Every list ranks Flutter and React Native first. Why doesn't this one rank at all?
Because the approaches do not compete on one axis. Flutter and React Native lead every adoption survey quoted above, and if popularity is your tiebreaker, that is data. This page’s position is that the two grid questions and the parity question predict your costs better than a rank — and that the right column for a web team, a Kotlin team and a Swift team is simply a different column of the table.
Duet projects are scaffolded by Modaal — starting a Duet project walks through the two template cards.
Sources and further reading
- Flutter FAQ and Impeller — rendering, app-size figures, governance
- React Native documentation and the React Foundation announcement
- Compose Multiplatform and Jetpack Compose and the 1.12.0 release post
- Kotlin Multiplatform on developer.android.com and JetBrains’ case studies
- Ionic documentation and Capacitor documentation
- .NET MAUI documentation and the Xamarin support policy
- Skip documentation — the transpiled and natively compiled modes
- Crux and UniFFI — the Rust-core prior art
- Stack Overflow Developer Survey 2024 — the last edition with the cross-platform category
- Escape-to-native routes, per framework: Flutter platform views and
Texture; React Native Fabric Native Components; JetBrains’ UIKit integration; .NET MAUI handler customization; Capacitor custom native code; Skip cross-platform topics - Kotlin/Native interoperability with Swift/Objective-C, .NET MAUI invoking platform code and the Capacitor workflow — which language the island is written in and what compiles it
- Apple’s
UIHostingController, Android’sComposeView, Expo Modules API and Expo UI — how SwiftUI and Compose enter a framework-drawn or React-driven screen - The Duet framework on GitHub — both flavors, the recording toolchain and the versioned contracts
Read next
Duet vs Flutter
The canvas-and-runtime model against the native-UI shared-core model, in depth.
Duet vs React Native
Both draw native views — the comparison is where logic runs and what checks the boundary.
Duet vs Compose Multiplatform
Same language decision, opposite UI decision — the nearest relative in the field.
The best iOS app architecture
The same comparison discipline one level down: TCA, RIBs, VIPER, MVVM, MVC and Clean, scored.
Modaal alternatives
The same comparison one level up: the app builders, not the frameworks they emit, on modaal.dev.