We run a B2B commerce app on React Native, in production, across multiple markets. Having also delivered native and hybrid stacks, here is the version of this comparison I wish I had read earlier — less enthusiastic than the advocacy, less dismissive than the criticism.
What it genuinely delivers
One product team, not two. This is the real prize and it is larger than the code sharing. Two native teams do not just write code twice; they reach different conclusions, ship at different times, and accumulate divergent behaviour that Product then has to reconcile. A single team produces one product.
Shared logic with the web. Commerce apps are mostly state, validation, formatting and API orchestration. That is genuinely reusable, and the parts that are not — layout, navigation, platform conventions — should not have been shared anyway.
A hiring pool that exists. Not a small consideration when you are staffing a mobile capability inside a larger organization rather than hiring a specialist native team.
What it costs
You inherit the ecosystem's upgrade cadence. Your platform is now a moving dependency with its own release rhythm, and falling behind compounds. This is the cost most teams underestimate — not any single upgrade, but the standing obligation.
The library layer is where the risk lives. Not the framework. The community packages between your code and the platform are where abandonment, breaking changes and hand-maintained patches accumulate. Every dependency you add is a future upgrade you have agreed to fund.
The most expensive code in a React Native codebase is usually not code you wrote. It is the patches you applied to code you did not.
Performance work needs specialists. Not because performance is unattainable — it is — but because diagnosing it requires understanding both the JavaScript layer and the native one, and engineers comfortable across that boundary are rarer than engineers comfortable in either.
The class of problem that stays hard
Memory on low-end devices. Rendering long lists of rich content smoothly. Anything touching platform-specific background behaviour. Deep integration with device capabilities that the ecosystem has not standardised.
These are tractable, and they will consume disproportionate senior time. If your product depends heavily on any of them, weigh that honestly rather than assuming the framework abstracts it away. It does not; it relocates it.
The dependency discipline
Treat every third-party package as an upgrade obligation you are signing, and audit them on a schedule rather than when something breaks. We removed 22 in a single programme and the upgrade that followed was dramatically cheaper for it. Duplicate-capability libraries — two packages doing the same job — are the easiest wins and almost always present.
Where I would not choose it
Apps whose core value is a platform-specific capability — heavy camera or media processing, deep OS integration, sustained background work. There the framework is friction against your differentiator, and the calculus inverts.
For commerce, where the product is catalogue, cart, checkout, account and content, the trade has been clearly correct for us. But that conclusion belongs to the product shape, not to the framework — and the teams I have seen regret the choice mostly picked it for velocity, then discovered that velocity was never the constraint.