Cross-Platform Mobile App Development with React Native
With React Native New Architecture (Fabric + JSI + TurboModules) in production with RN 0.71+, the stack architecture changed radically. JSI (JavaScript Interface) replaced the asynchronous bridge with a synchronous C++ interface — native modules are now called directly from JS without serialization through JSON. Fabric rewrote the renderer from scratch: UI tree builds through C++ Shadow Tree, not through a separate Native UI thread by the old scheme.
In practice, this means RN 0.73+ applications with New Architecture enabled behave differently than those written a year ago — some old libraries without TurboModules support simply won't work or will require enableLegacyBridge. When starting a new project we always use New Architecture; when migrating existing — dependency audit is mandatory.
Where real complexity manifests
Metro bundler and exotic dependencies. If the project has native modules with custom C++ extensions, Metro can't resolve without metro.config.js fixes. Typical crash: Unable to resolve module with symlinks in monorepo — solved via resolver.unstable_enableSymlinks: true + watchFolders.
Animation. Animated API works through JS thread — under load animation stutters. Correct answer: react-native-reanimated 3.x with worklets, which run on UI thread directly via JSI. react-native-gesture-handler instead of base TouchableOpacity — only this way gestures are handled natively without 16ms JS bridge delay.
We saw crashes on Android 13 in a delivery app: react-native-camera didn't handle new READ_MEDIA_IMAGES permissions (replaced deprecated READ_EXTERNAL_STORAGE). Had to switch to react-native-vision-camera 3.x — it supports Camera2 API and Skia Frame Processors for real-time frame processing.
Fonts and RTL. Custom fonts via react-native-fonts break layout with RTL locales (Arabic, Hebrew) if I18nManager.allowRTL(true) is not set and Flexbox styles aren't tested with start/end instead of left/right.
Stack and architectural decisions
State management: Zustand for simple projects, Redux Toolkit + RTK Query for complex ones. Redux Saga used only in teams with existing expertise — new Saga code isn't worthwhile. MobX — where many interdependent reactive states exist.
Navigation — React Navigation 6.x with native stacks (@react-navigation/native-stack via react-native-screens). Expo Router suitable for Expo-managed projects with file-based routing.
For Expo projects — SDK 50+, EAS Build for CI/CD instead of local builds. EAS Submit automates App Store Connect and Google Play Console uploads. For bare React Native — Fastlane + GitHub Actions.
Local storage: MMKV (via react-native-mmkv) instead of AsyncStorage — synchronous, fast, written in C++. For relational data — WatermelonDB with lazy loading, suitable for offline-first apps with sync.
Case study. Marketplace with 40+ screens, real-time chat via WebSocket, payments via Stripe (@stripe/stripe-react-native). Long list rendering — FlashList from Shopify instead of FlatList: FlatList with 500+ cards gave jank on mid-range Android, FlashList with its own recycler solved the problem. OTA-updates — react-native-code-push for hotfixes without store release. Crash-reporting — Firebase Crashlytics via @react-native-firebase/crashlytics.
Testing
Unit tests — Jest + @testing-library/react-native. Component tests: render + fireEvent + snapshot for critical components. E2E — Detox (recommended) or Maestro. Detox requires setup per platform but gives reliable tests on real simulators.
Performance analysis — react-native-performance + Flipper with Performance Monitor plugin. For JS profiling — Chrome DevTools via Metro debugger.
Timelines and scope
| Scope | Approximate timeline |
|---|---|
| MVP, up to 10 screens, REST | 6–10 weeks |
| Product with auth, maps, push | 3–5 months |
| Complex platform: chat, payments, offline | 6–12 months |
Cost calculated individually per specification. After requirements audit we fix scope, stack and phases.







