🚀 Lessons from Scaling a React Native App to 1M+ Users


When you’re building for a few hundred users, development feels straightforward: add a feature, test it, release it, repeat. But when your app crosses 1 million users, that simplicity disappears — fast. Suddenly, every decision has scale implications, and tiny cracks in your architecture become glaring system faults.
This post isn’t a collection of best practices you’ve already read on Medium. These are real lessons — earned through late-night outages, debugging marathons, and growing pains — from scaling a React Native app to over 1 million users.
1. Performance Is a Feature — Treat It Like One
At 10K users, we were proud of our animations. At 100K users, we started seeing lag reports. At 1M users? Crashes on older Android devices and rising uninstall rates.
One specific issue: our cold start time on low-end Android phones exceeded 6 seconds, and 15% of sessions crashed due to memory overflows. That was a serious wake-up call.
What helped us:
Removed bulky, unmaintained libraries.
Introduced Flipper, React DevTools, and
why-did-you-render
to catch render bottlenecks.Replaced
FlatList
with FlashList for better virtualization performance.Lazy-loaded screens and large image assets.
Takeaway: What works at dev scale breaks at real-world scale. Measure cold starts, memory usage, and unnecessary re-renders early and often.
2. Architecture Must Evolve — Or You’ll Sink in Your Own Code
As feature velocity picked up, we started drowning in technical debt. Every new feature caused regressions. Developers hesitated to refactor. Productivity tanked.
So, we re-architected from scratch using Clean Architecture principles:
cssCopyEdit📦 src/
┣ 📁 features/
┃ ┗ 📁 chat/
┃ ┣ 📁 components/
┃ ┣ 📁 hooks/
┃ ┣ 📁 services/
┃ ┗ 📁 screens/
┣ 📁 shared/
┣ 📁 core/ (infrastructure, types, constants)
We also ditched Redux in favor of Zustand, which offered:
A hook-first API
Minimal boilerplate
Scoped state slices for better separation of concerns
Takeaway: You don’t scale code by writing more of it. You scale it by organizing it for change.
3. Release Strategy Isn’t Just DevOps — It’s Damage Control
A single crash in production now meant thousands of users affected in minutes. One bad push cost us our Play Store rating.
We needed to ship safely, not just quickly.
What saved us:
Feature Flags via Firebase Remote Config for instant kill switches.
Expo OTA Updates + EAS for hotfixes without waiting for app store review.
Multi-environment CI/CD with Bitrise: staging, QA, beta, production.
We even rolled out a release checklist that all engineers had to follow.
Takeaway: Releases aren’t about shipping features. They’re about preserving trust.
💬 Question: How do you manage emergency rollbacks in your app?
4. Crash Reports ≠ User Experience
Crash reports tell you what broke. They don’t tell you what feels broken to users.
We started tracking:
Cold Start Time and Time to First Paint
UI blocking operations
Funnel drop-offs using Amplitude
Custom logs for “rage clicks” and long response waits
This helped us detect pain points before they turned into reviews or tickets.
Takeaway: If you’re only looking at crashes, you’re already too late.
5. Your Team Will Be Your Bottleneck (or Superpower)
Code scales faster than humans. We learned this when onboarding new devs took 3+ weeks, and PRs became unreviewable beasts.
What helped:
Introduced codeowners and feature ownership.
Used ESLint, Prettier, and commit hooks for consistency.
Documented architecture, dev processes, and gotchas in Notion.
Scheduled weekly refactoring time as a team-level investment.
Takeaway: An unscalable team produces unscalable code.
💬 Question: How do you onboard new devs efficiently in large React Native projects?
6. Backend Isn’t “Separate” — It’s Half of the App
Early on, we treated the backend as “another team.” This caused misaligned assumptions, slow iterations, and nasty API surprises.
To fix that:
We switched to GraphQL, giving mobile devs more flexibility and fewer over-fetches.
Created a shared API schema via Zod and Swagger.
Added end-to-end tests for mobile+backend contracts.
Held weekly syncs between frontend/backend leads to align product direction.
Takeaway: You don’t scale React Native in isolation. You scale the entire ecosystem behind it.
🔚 Final Thoughts
Scaling a React Native app to a million users isn’t just about writing efficient code — it’s about building systems, making smart decisions, and learning faster than your problems grow.
If you’re somewhere on that path — early, mid-scale, or hitting architecture limits — I hope this helped shortcut some of your pain.
Let’s not pretend this journey is easy — but it is possible, and incredibly rewarding.
💬 Your Turn
Which of these lessons resonates most with you?
What would you do differently based on your own scale journey?
Drop a comment — I read every one.
👋 Stay Connected
Follow me for more posts on:
React Native at scale
Mobile architecture & performance
Real-world dev leadership
You can also find me on LinkedIn.
Subscribe to my newsletter
Read articles from Lav Pranjale directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
