When React Native is a strong fit
React Native renders real platform views, so controls such as text inputs, scroll views and navigation feel native by default. It suits products where the team already works in React, where a web app and a mobile app share business rules, and where shipping small fixes quickly matters.
- Companies with an existing React or Next.js web product adding mobile apps
- Content, commerce and marketplace apps built around lists, forms and media
- B2B apps where speed of iteration and a single TypeScript codebase outweigh platform-specific polish
- Products that benefit from over-the-air fixes between store releases
If your team has no React background and the design is heavily custom, Flutter may be the simpler choice. Both are covered in our overview of cross-platform frameworks.
The New Architecture: Fabric, TurboModules and JSI
React Native's New Architecture is now the default for new projects, and the legacy asynchronous bridge is being phased out. For anyone starting or inheriting a React Native app, it is the single most important technical consideration.
| Area | Legacy architecture | New Architecture |
|---|---|---|
| JavaScript to native calls | Asynchronous bridge with JSON serialization | JSI: direct calls into C++ host objects |
| Native modules | Loaded at startup | TurboModules: typed and lazily loaded |
| Rendering | Asynchronous UI manager | Fabric renderer with synchronous layout when needed |
| Type safety | Manual | Codegen from TypeScript specs |
| React features | Limited concurrent rendering | Supports concurrent React features such as transitions |
For existing apps, migration mostly means upgrading React Native, replacing or updating libraries that have not adopted the new APIs, and converting custom native modules. We audit dependencies first, since one unmaintained library is usually what blocks an upgrade.
The practical benefits show up in day-to-day product work. Synchronous layout measurement removes the flicker that used to appear when positioning tooltips or popovers. Gesture-driven animations stay smooth because they no longer queue behind bridge traffic. Native modules declared with TypeScript specs give compile-time errors when the JavaScript and native sides disagree, instead of crashes discovered in QA. For new projects, none of this requires extra effort; it is simply how a current React Native app is built.
Expo, bare workflows and native modules
Expo is now the framework the React Native team recommends for new apps. It no longer means giving up native code: development builds and config plugins let us add any native SDK while keeping Expo's tooling.
- Expo Router for file-based navigation and deep linking that mirrors web routing
- EAS Build for reproducible cloud builds with managed signing credentials
- EAS Submit to push builds to TestFlight and Google Play tracks from CI
- Expo Modules API for writing our own native modules in Swift and Kotlin
- Continuous native generation, so iOS and Android project files are generated from config rather than hand-edited
Around that we typically use TypeScript in strict mode, TanStack Query for server state, Zustand or Redux Toolkit for client state, Reanimated for gesture-driven animation and FlashList for long lists. The full toolchain is described on our React Native technology page.
Over-the-air updates done responsibly
Because a React Native app's JavaScript bundle can be replaced at runtime, teams can ship fixes without waiting for store review. Apple and Google allow this for code that does not change the app's primary purpose or bypass review of new functionality, so we use OTA updates for fixes and small adjustments, not new features.
Safeguards we put in place
- Runtime versions so an update only reaches binaries with matching native code
- Separate channels for staging and production, with promotion between them
- Percentage rollouts and the ability to roll back to the embedded bundle
- Crash monitoring with source maps uploaded for every update
What we build with React Native
React Native projects we take on fall into a few patterns, each with its own technical emphasis. Identifying the pattern early helps us choose libraries and plan the parts that will need native code.
- Mobile companions to an existing web product, sharing API clients, types and validation through a monorepo
- Commerce and content apps where list performance, image caching and deep links from marketing campaigns matter
- Field and operations apps with offline storage using SQLite-based libraries and background sync
- Apps embedding vendor SDKs, such as identity verification, payments or video calling, wrapped as native modules
Working alongside your web engineers
One advantage of React Native is that your existing React engineers can contribute to the mobile app. We set up the repository so that is practical: shared lint rules and TypeScript configs, a shared package for domain logic, and documentation on the mobile-specific parts such as navigation, permissions and release builds. Over time, many of our clients move mobile ownership in-house, and we design the handover from the first sprint.
Inheriting an existing React Native app
React Native apps built several years ago often sit on old versions, a mix of JavaScript and TypeScript, and libraries that have since been deprecated. Upgrades get harder the longer they wait, and at some point store requirements for new SDK versions force the issue.
- Inventory every dependency and check its New Architecture support and maintenance status
- Stabilize the build on CI so upgrades can be verified automatically on both platforms
- Upgrade React Native in planned steps, using the official upgrade helper to track native file changes
- Introduce TypeScript and tests incrementally around the code being touched
- Evaluate moving to Expo tooling once the app is on a current version
Performance and testing
Hermes, the JavaScript engine built for React Native, compiles JavaScript to bytecode at build time, which shortens startup. Most performance problems we see come from unnecessary re-renders, large unvirtualized lists and heavy work on the JavaScript thread, so we profile with React DevTools and platform tools early.
Testing combines Jest and React Native Testing Library for components and logic, and Maestro or Detox for end-to-end flows on real devices. Our mobile app development process article explains where each layer of testing fits in a release cycle.
Cost and timeline
React Native projects fall within the same broad ranges as other cross-platform work: roughly $30k–$90k for an MVP and $60k–$150k for a mid-complexity app, varying with scope and integrations. Reusing types, validation logic and API clients from an existing web codebase can reduce effort further.
Ongoing costs deserve a line in the budget too. React Native and its major libraries release regularly, and Apple and Google raise SDK requirements each year, so we recommend planning for a version upgrade at least once or twice a year. EAS and similar build services have their own usage-based pricing, which is usually small next to engineering time but worth confirming for apps that release often.
If you are weighing frameworks on budget, our guide to app development costs compares the drivers that matter more than framework choice.