PATTERN Cited by 1 source
Mixed native plus cross-platform mobile stack¶
Problem¶
A cross-platform mobile framework (React Native, Flutter, Kotlin Multiplatform, etc.) lets a team write most features once and ship to iOS and Android from one codebase. The naive reading of that capability is "therefore write everything in the cross-platform framework." That reading fails in production: the framework doesn't cover device- hardware APIs equally, has memory-footprint limits on constrained surfaces (home-screen / lock-screen widgets, watch apps), and can't efficiently run long-running background jobs.
Solution¶
Treat cross-platform framework and native code as complementary tools, not alternatives. The architectural rule:
"Think native and React Native, not native or React Native." — Mustafa Ali, Shopify
"100% React Native should be an anti-goal" — ship most feature-parity-critical surfaces in the cross-platform framework (feature-parity is a non-issue because you wrote it once), and ship native code for the categories where native is the right tool:
- Device hardware — camera-based 2D/3D scanning, on- device AI / ML inference, Bluetooth / NFC / sensors.
- Memory-constrained surfaces — iOS home-screen widgets, lock-screen widgets, Apple Watch apps and complications, App Intents, Siri Shortcuts. These run in tightly memory- budgeted extension processes where a JS runtime + RN bundle is a non-starter.
- Long-running background jobs — RN's JS runtime typically runs in the app's foreground process and is suspended when the app is backgrounded. Tasks that need to keep running (data sync, transaction processing while offline, content caching) live in native background-task APIs. Shopify Point of Sale's canonical example: "downloads and syncs a ton of data in the background so that it can process transactions even when offline. By leveraging native code, we were able to offload that work completely to the background, ensuring that it had no effect on app performance."
Enabler: strong JS↔native interop¶
The mixed stack only works if calling native from JS (and vice versa) is ergonomic. React Native's bridge (legacy) and JSI + TurboModules + Fabric (New Architecture) both serve this role; Flutter's platform channels play the equivalent role. The Shopify retrospective credits this interop: "Doing so is easy thanks to strong interoperability that RN provides out of the box."
Organisational implication: mixed team shape¶
The mixed stack implies a mixed-expertise team: native iOS engineers + native Android engineers + web engineers (for JS / TS / React fluency) + RN specialists. No single expertise covers all three surfaces. Native engineers own the platform- layer work (widgets, background jobs, performance tuning across device models, version upgrades — see patterns/rotating-framework-upgrade-team); RN-familiar engineers (originating from either native or web) build the shared feature surface. Shopify's training posture: self-serve RN course for native devs + office hours with proficient RN devs + supplementing mobile teams with web devs for JS / TS / React expertise.
When to use¶
- You're running a consumer app at scale where feature- parity between iOS and Android matters (e.g. Shopify merchant app, Shop app, POS app, inbox app).
- You need to access platform-specific hardware or memory- constrained surfaces that don't cleanly live in the cross- platform framework (most non-trivial consumer apps).
- You have native engineers on staff or can hire / train them — this pattern requires native expertise even after RN adoption.
When not to use¶
- Thin wrapper apps where all features are feature-parity- trivial and no native-only surfaces are needed — 100% RN (or 100% Flutter) is a viable answer here.
- Small teams that can't afford mixed expertise — pick the single framework that best fits your dominant surface.
- B2B apps with fixed platform — if you only ship iOS, a native iOS stack may be the right answer.
Seen in¶
- sources/2025-01-13-shopify-five-years-of-react-native-at-shopify — Canonical statement of the pattern. Shopify Mustafa Ali's five-year retrospective: "100% React Native should be an anti-goal. It is great for building features just once, but is not the right technology for everything. ... Instead of thinking native or React Native, think native and React Native." Shopify apps hit <500ms (P75) screen loads
-
99.9% crash-free sessions with this posture. Shopify POS is the canonical mixed-stack example — RN feature surface + native background-sync.
Related¶
- systems/react-native — The cross-platform framework Shopify runs; the pattern generalises to Flutter / KMP etc.
- concepts/cross-platform-client-library — Adjacent concept at the single-library altitude (vs this pattern's whole-app-framework altitude).
- concepts/shared-mobile-foundations — The follow-up discipline: extracting shared components across the mixed stack once per-app maturity is reached.
- patterns/rotating-framework-upgrade-team — The staffing pattern that absorbs framework upgrades without stalling feature velocity on the mixed stack.
- companies/shopify