Performance

Scaling React Native Apps for Millions of Users

Amol BadheOctober 15, 20257 min
Scaling React Native Apps for Millions of Users

Over the past 10 years, we've built and scaled React Native apps for 50+ news properties serving millions of users across 22 countries. Here are the key lessons we've learned.

The Challenge

News apps face unique scaling challenges:

  • Breaking news spikes: 10x traffic during major events
  • Real-time updates: Push notifications to millions
  • Rich media: Videos, images, live streams
  • Offline support: Read news without connectivity
  • Personalization: AI-powered content recommendations

Architecture Patterns

1. Modular Architecture

We organize our apps using a modular architecture:

/features
  /articles
  /videos
  /breaking-news
  /personalization
/shared
  /components
  /utils
  /api

Each feature is self-contained with its own:

  • Components
  • State management
  • API layer
  • Tests

2. State Management at Scale

For large-scale apps, we use Zustand with persistence:

import create from 'zustand';
import { persist } from 'zustand/middleware';

const useArticleStore = create(
  persist(
    (set) => ({
      articles: [],
      favorites: [],
      addFavorite: (article) =>
        set((state) => ({
          favorites: [...state.favorites, article],
        })),
    }),
    { name: 'article-storage' },
  ),
);

Performance Optimizations

1. List Virtualization

For infinite article lists:

import { FlashList } from '@shopify/flash-list';

<FlashList
  data={articles}
  renderItem={({ item }) => <ArticleCard article={item} />}
  estimatedItemSize={200}
  onEndReached={loadMore}
  onEndReachedThreshold={0.5}
/>;

2. Image Optimization

import FastImage from 'react-native-fast-image';

<FastImage
  source={{
    uri: article.imageUrl,
    priority: FastImage.priority.normal,
  }}
  resizeMode={FastImage.resizeMode.cover}
  style={styles.image}
/>;

3. Code Splitting

Use dynamic imports for heavy features:

const VideoPlayer = lazy(() => import('./VideoPlayer'));

// In component
<Suspense fallback={<Loader />}>
  <VideoPlayer />
</Suspense>;

Real-Time Updates

WebSocket Connection

import { io } from 'socket.io-client';

const socket = io('wss://api.news.com', {
  transports: ['websocket'],
  reconnection: true,
  reconnectionDelay: 1000,
  reconnectionAttempts: 5,
});

socket.on('breaking-news', (article) => {
  showBreakingNewsAlert(article);
  updateArticleList(article);
});

Push Notifications

We use Firebase Cloud Messaging with custom segmentation:

messaging().onMessage(async (remoteMessage) => {
  const { category, priority } = remoteMessage.data;

  if (priority === 'breaking') {
    showBreakingAlert(remoteMessage);
  } else {
    showRegularNotification(remoteMessage);
  }
});

Offline Support

Local Database

We use WatermelonDB for offline article storage:

import { Database } from '@nozbe/watermelondb';

const database = new Database({
  adapter: new SQLiteAdapter({
    schema,
    dbName: 'NewsApp',
  }),
  modelClasses: [Article, Category],
});

Sync Strategy

async function syncArticles() {
  const lastSync = await getLastSyncTime();

  const newArticles = await api.getArticles({
    since: lastSync,
    limit: 100,
  });

  await database.write(async () => {
    for (const article of newArticles) {
      await articlesCollection.create((a) => {
        a.title = article.title;
        a.content = article.content;
        a.syncedAt = Date.now();
      });
    }
  });
}

AI-Powered Personalization

Content Recommendations

async function getPersonalizedFeed(userId) {
  // Track reading behavior
  const readingHistory = await getUserReadingHistory(userId);

  // Call recommendation API
  const recommendations = await api.getRecommendations({
    userId,
    history: readingHistory,
    count: 20,
  });

  return recommendations;
}

A/B Testing

import { useExperiment } from '@/hooks/useExperiment';

function ArticleList() {
  const variant = useExperiment('article-card-design');

  return (
    <FlashList
      renderItem={({ item }) =>
        variant === 'A' ? <ArticleCardA article={item} /> : <ArticleCardB article={item} />
      }
    />
  );
}

Monitoring & Analytics

Performance Monitoring

import analytics from '@react-native-firebase/analytics';
import perf from '@react-native-firebase/perf';

// Track screen load time
const trace = await perf().startTrace('article_load');
await loadArticle(id);
await trace.stop();

// Track user engagement
await analytics().logEvent('article_read', {
  article_id: id,
  category: category,
  read_duration: duration,
});

Error Tracking

import crashlytics from '@react-native-firebase/crashlytics';

try {
  await loadArticles();
} catch (error) {
  crashlytics().recordError(error);
  crashlytics().log('Failed to load articles');
}

Deployment Strategy

Over-The-Air Updates

We use CodePush for rapid fixes:

import codePush from 'react-native-code-push';

const App = () => {
  // ... app code
};

export default codePush({
  checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
  installMode: codePush.InstallMode.ON_NEXT_RESUME,
})(App);

Staged Rollouts

  1. 10% rollout: Monitor for 24 hours
  2. 50% rollout: Check crash rates
  3. 100% rollout: Full deployment

Key Metrics

We track:

  • App Load Time: < 2 seconds
  • Article Load Time: < 500ms
  • Crash-Free Rate: > 99.9%
  • Memory Usage: < 150MB average
  • FPS: Consistent 60fps scrolling

Lessons Learned

  1. Invest in monitoring early: You can't optimize what you can't measure
  2. Test on low-end devices: Flagship phones hide problems
  3. Offline-first thinking: Network is unreliable
  4. Incremental rollouts: Catch issues before they scale
  5. Keep bundle size small: Every KB matters on slower connections

Conclusion

Scaling React Native apps to millions of users requires careful architecture, performance optimization, and robust monitoring. These patterns have served us well across 50+ news properties.

Resources

Need help building your mobile app?

Let's talk about how we can help you design, build, and scale a high-performance React Native app tailored to your users.

Talk to an Expert