| name | mobile-tech-stack-selection |
| description | Decision framework for choosing between native iOS/Android, Flutter, React Native, and Kotlin Multiplatform for a new or migrating mobile project. Use when the stack is undecided or being revisited. |
Mobile Tech Stack Selection
Instructions
Stack choice is a one-way door for most of the codebase. Use an explicit decision framework rather than taste. The goal is to pick the stack whose strengths match the project's constraints.
1. Candidate Stacks (2026 baseline)
- Native iOS -- Swift 5.9+, SwiftUI + UIKit interop, Xcode 15+.
- Native Android -- Kotlin 1.9+, Jetpack Compose + View interop, AGP 8+.
- Flutter -- Dart 3.4+, Flutter 3.22+, Impeller renderer.
- React Native -- 0.74+ with New Architecture (Fabric + TurboModules), usually via Expo SDK 51+.
- Kotlin Multiplatform (KMP) -- Kotlin 1.9+, shared business logic, Compose Multiplatform for UI when desired.
- Native + KMP shared logic -- SwiftUI + Compose with a shared Kotlin domain module.
2. Decision Dimensions
Score each stack against the project on these dimensions:
| Dimension | Weight signal |
|---|
| Time-to-first-build on both platforms | Small team, tight deadline -> high |
| Platform API reach (Bluetooth, ARKit, CameraX, HealthKit) | Deep native integration -> native wins |
| UI fidelity with platform conventions | Banking, productivity apps -> native or KMP+native UI |
| Shared business logic reuse | Complex domain, multiple clients -> KMP shines |
| Hot reload / iteration speed | Rapid design iteration -> Flutter, RN |
| Binary size sensitivity | Emerging markets, tight APK -> native |
| Team skillset | Existing Kotlin team -> KMP/Android; web team -> RN |
| Hiring pool in your geography | Plain Android/iOS typically deepest |
| Long-term maintenance risk | Stack longevity, vendor neutrality |
3. Default Recommendations
- Two engineers, consumer content app, need both platforms fast: Flutter or React Native.
- Existing web/React team, content-heavy app with some native integrations: React Native with Expo.
- Consumer app with heavy native surface (AR, ML, camera) and bespoke UI: native, possibly with KMP for shared logic.
- Fintech / regulated app needing exact platform behavior: native. Treat cross-platform as a last resort.
- Productivity app with complex domain rules and multiple clients (mobile + desktop): KMP core + native UI, or Compose Multiplatform.
- Internal/enterprise tool with low UX bar, short TTM: React Native or Flutter.
4. Cross-Platform Parallels
The same "show a user name" problem in each stack, so the agent can reason about equivalence:
struct UserView: View {
let name: String
var body: some View { Text(name).font(.headline) }
}
@Composable
fun UserView(name: String) {
Text(name, style = MaterialTheme.typography.titleMedium)
}
// Dart / Flutter
class UserView extends StatelessWidget {
const UserView({super.key, required this.name});
final String name;
@override
Widget build(BuildContext context) =>
Text(name, style: Theme.of(context).textTheme.titleMedium);
}
export function UserView({ name }: { name: string }) {
return <Text style={{ fontSize: 20, fontWeight: '600' }}>{name}</Text>;
}
5. Decision Record Template
Write the outcome as an ADR. Do not let it live in Slack.
# ADR-001: Mobile Stack
## Status
Accepted 2026-04-19.
## Context
- Team: 3 engineers (2 Android/Kotlin, 1 iOS/Swift).
- Product: B2C fitness tracker, heavy HealthKit/Google Fit integration.
- Constraints: 4-month MVP, both platforms at launch.
## Options considered
1. Native iOS + Native Android
2. Flutter
3. React Native (Expo)
4. KMP + native UI
## Decision
KMP shared domain + native UI on each platform.
## Consequences
+ Native HealthKit / Health Connect access with no plugin lag.
+ Domain rules written once.
- Initial setup cost; KMP toolchain maturity on iOS requires attention.
- Hiring for iOS + KMP is narrower than pure iOS.
6. Review Triggers
Revisit the stack decision when:
- The primary use case shifts (e.g., adding AR, video editing).
- Binary size or startup time blocks a launch gate.
- Two consecutive OS releases require workarounds in the framework.
- The team composition changes materially.
7. Anti-Patterns to Refuse
- "React Native is cheaper" without accounting for native module work.
- "We will adopt KMP incrementally starting with UI." UI is the hardest KMP surface; start with networking/domain.
- "Just use whatever we used last project." Re-score against this project.
- "Flutter cannot do X" without citing a current source; capabilities move quickly.
Checklist