
We Shipped a React Native App to 1.2 Million Users. Here Are the 7 Things We Wish We Knew on Day One.
- Larry Brooks
- Software, Strategy
- 18 Jun, 2026
At 1,000 users, React Native felt effortless. At 100,000 users, cracks appeared. At 1.2 million users, everything we assumed about mobile development was tested. Seven lessons stood out — each one learned through production incidents we could have prevented.
1. OTA Updates Are a Superpower Until They Break
Over-the-air updates let us push JavaScript changes without App Store review. We shipped fixes in hours instead of days. Then a malformed OTA update crashed the app for 340,000 users simultaneously.
The lesson: OTA updates need the same staged rollout discipline as native releases. We now deploy OTA updates to 1% of users, monitor crash rates for 2 hours, then expand to 10%, 50%, and 100%. The days of pushing to everyone at once are over.
2. The Long Tail of Android Devices Is Longer Than You Think
Our device matrix covered 23 Android devices. Our users had 2,400 distinct device models. The device matrix caught 80% of issues. The remaining 20% — custom OEM Android skins, unusual screen aspect ratios, aggressive battery optimization that kills background processes — generated 60% of our support tickets.
The lesson: Firebase Test Lab's device farm is not optional. Automated smoke tests on 50+ device configurations catch the issues your manual matrix misses.
3. Navigation Performance Is the Metric Users Feel
Users do not time your API calls. They feel your navigation transitions. A 300ms screen transition feels instant. A 500ms transition feels acceptable. A 700ms transition feels slow. An 1,100ms transition generates one-star reviews.
The lesson: profile navigation transitions on your lowest-spec target device, not your development machine. We set a 400ms budget for screen transitions and treat violations as P1 bugs.
4. Crash-Free Rate Is the Only Metric That Matters
Feature velocity, test coverage, code quality — none of it matters if the app crashes. Users forgive slow performance. They do not forgive crashes. Our target is 99.5% crash-free sessions. Below that threshold, we stop feature work and fix stability.
The lesson: instrument crash reporting before writing the first feature. Sentry with Hermes source maps gives us symbolicated crash reports with JavaScript and native stack traces within 30 seconds of a crash.
5. Deep Linking Will Break in Ways You Cannot Predict
App links, universal links, custom URL schemes, push notification deep links, deferred deep links from marketing campaigns — each has its own configuration, its own failure modes, and its own platform-specific quirks. We spent more time debugging deep linking than any single feature.
The lesson: build a deep link testing harness that validates every link path on every platform after every release. Manual testing cannot cover the combinatorial complexity.
6. Accessibility Is Not Optional
15% of our users relied on screen readers or dynamic text sizes. We discovered this after shipping an update that broke VoiceOver navigation. The support response was immediate and intense.
The lesson: accessibility testing is part of the definition of done, not a separate initiative. Every screen must be navigable with VoiceOver (iOS) and TalkBack (Android), and every text element must respond to dynamic type.
7. Your State Management Will Be Rewritten
We started with Redux. Migrated to MobX. Settled on Zustand and React Query. Each migration was expensive. The third one stuck because we finally understood what we needed — not what blog posts recommended.
The lesson: delay your state management architecture decision as long as possible. Start with React's built-in state. Add external tools only when you hit a concrete limitation, not a theoretical one.
If you are scaling a React Native app and want to skip the expensive lessons, let's work together.
