Five Years of React Native at Shopify
What Shopify learned after migrating all their mobile apps to React Native over five years — including where the framework genuinely wins, where it still falls short, and why 100% React Native should be an anti-goal.

The assumption that React Native is a performance compromise has been repeated so often it has become axiomatic. Shopify shipped sub-500ms P75 screen loads across their entire mobile portfolio using it. The compromise is real — but it is not where most people think it is.
Source
Five years of React Native at Shopify
By: Shopify
Published: Jan 13 2025
Type: Engineering article
Saved because this is the most honest long-form account of React Native at production scale that has been published. Most write-ups are either advocacy pieces that gloss over problems or skeptical posts that list limitations without showing whether those limitations can be worked around. Mustafa Ali, Director of Engineering at Shopify, names both sides with specifics and actual numbers.
What Five Years Actually Taught Them
Shopify made the React Native bet in 2019 for three stated reasons: write features once instead of twice, make engineers portable across iOS, Android, and web, and spend more time shipping value instead of chasing feature parity. Five years later, all their apps have completed the migration. The headline outcome — sub-500ms P75 screen loads, greater than 99.9% crash-free sessions — is the number that kills the performance-compromise narrative most cleanly, but it is only credible if you understand what it took to get there.
The first and most important lesson is one that the article states plainly but that most performance conversations ignore: native does not automatically mean fast, and React Native does not automatically mean slow. Every React Native performance problem the Shopify team encountered turned out to be solvable with the right patterns and techniques. The difficulty is that React Native gives you fewer guardrails than native code. The framework does not stop you from doing things on the main thread that should be off it, from re-rendering components that do not need to change, or from loading a route’s entire dependency tree synchronously before showing anything. Native development has the same pitfalls — UIKit will happily let you block the main thread too — but years of platform conventions, Instruments profiling tooling, and code review culture have made those antipatterns more visible. React Native’s conventions are younger, the profiling story is more fragmented, and institutional knowledge about what fast RN code looks like is still accumulating. The path to 500ms screen loads is not choosing the right framework; it is applying the right techniques inside whichever framework you are in.
The hot reloading story matters more than it appears in the article. Shopify’s native codebases had grown large enough that a trivial change could take several minutes to compile, deploy to a simulator, and reach the changed screen. That wait breaks developer flow in a way that compounds: engineers write bigger changes to amortize the compile cost, which makes code review harder and makes bugs harder to localize. Hot reloading eliminates the cost, which means engineers write smaller, more focused changes, which means the codebase evolves more safely. The performance of the development loop is a component of software quality, not just developer comfort.
TypeScript was not an obvious part of the React Native value proposition in 2019, but Shopify’s experience suggests it is central to the talent portability story. Web engineers transitioning to mobile using React Native were able to contribute to production code far faster than they could have on native iOS or Android. Mobile engineers familiar with React Native found it easy to work on web. This is not just a staffing convenience — it creates a culture where engineers see platforms as tools rather than identities, which means good ideas from one platform get applied to another instead of staying siloed. The Shopify app and their web storefront now share infrastructure components because the same engineers can work on both.
The most important corrective in the article is the argument against 100% React Native. The team found that native remains the right choice for cutting-edge hardware features (2D/3D scanning, on-device AI models), memory-constrained contexts (home screen widgets, Apple Watch complications, App Intents), and long-running background jobs. Their Point of Sale app downloads and syncs a significant volume of data in the background so that merchants can process transactions offline. Doing that work in React Native would affect app performance because RN background execution constraints on both iOS and Android are tighter than native. Dropping to native code — which React Native’s interoperability story makes straightforward — meant the background sync had no effect on the foreground app at all. The framework’s value is not eliminating native code; it is shrinking the set of places where you actually need it.
Three areas remain genuinely difficult. Debugging in React Native is fragile, and configuring it in VSCode requires effort that debugging in Xcode or Android Studio does not. Meta shipped a complete rewrite of the React Native debugger stack, and Shopify is collaborating with them on it — but as of writing it is still not at the same level as the platform tools. React Native version upgrades require substantial work and often restructure the codebase; Shopify handles this with a rotating team of engineers who focus on upgrades while the rest of the team continues feature development. And third-party library dependency is higher than on native, which adds ongoing maintenance burden and a wider supply chain attack surface. Shopify automated dependency updates with Dependabot and added automated code scanning for malicious code, but the surface area is real.
The shared foundations investment that accelerated in 2024 is the least covered but strategically most important development. In the early years, each team built things their own way because they were all learning React Native simultaneously and there was no accumulated wisdom to codify. By 2023, the apps were mature enough to extract common infrastructure — identity, real-time monitoring, performance measurement — into shared libraries. Every app now benefits automatically when those libraries improve. The tradeoff they made early (optimize for speed over consistency) was correct given their knowledge at the time; the tradeoff they are making now (extract shared foundations) is correct given the maturity they have reached.
My take
The part of this article that most write-ups will miss is the explicit statement that 100% React Native is an anti-goal. That framing inverts the usual advocacy posture. Most ecosystem articles want to show that the technology can do everything, because admitting limitations feels like weakness. Shopify’s framing is the opposite: knowing precisely where native is still the right tool is a sign of maturity, not failure. The teams that struggle with React Native performance are usually the ones trying to use it everywhere, including the places where it genuinely does not belong. Knowing the boundary is part of the skill.
Where this is useful
- Planning a React Native migration and trying to set realistic expectations for team structure (native expertise is non-negotiable, not legacy)
- Evaluating whether React Native can hit your performance targets (it can, with the right profiling discipline and the right patterns)
- Deciding which features to build in native versus React Native (hardware features, background jobs, and memory-constrained extensions belong in native)
- Not applicable for apps whose core value is cutting-edge device hardware integration — if your app is mostly 3D scanning or always-on background processing, the native-code proportion will be so high that the write-once benefit largely disappears
Apply this: Before each new feature, explicitly decide whether it belongs in React Native or native — treat native as the right tool for specific jobs, not as a fallback for when RN fails.
What I want to remember
Remember: React Native performance is not a framework property; it is a discipline — and knowing which features still belong in native code is part of that discipline, not an admission that the framework failed.