Module Overview
Estimated Time: 4 hours | Difficulty: Advanced | Prerequisites: Performance Optimization, Debugging modules
- React DevTools Profiler
- Flipper performance plugins
- Native profiling tools
- Production monitoring setup
- Custom performance metrics
- APM integration
Performance Profiling Overview
React DevTools Profiler
The React Profiler answers the question: “Which components are rendering, how often, and how long does each render take?” This is your first stop when investigating JavaScript-thread performance issues. The key insight: a component re-rendering is not inherently bad — re-rendering unnecessarily (with the same props and state) is where performance is wasted.Setting Up Profiler
Custom Profiler Component
Flipper Integration
Setup Flipper
Custom Flipper Plugin
Performance Tracking Hook
Native Profiling Tools
iOS Instruments
Android Profiler
Systrace Integration
Custom Performance Metrics
Built-in tools show you what is happening during development, but production is where performance actually matters. Users on 3-year-old Android phones with spotty cellular connections experience your app very differently from your development MacBook. Custom metrics bridge this gap by collecting timing data from real user sessions. The pattern below is a lightweight performance tracking service that measures arbitrary operations, buffers the results, and flushes them to your backend after interactions complete (so the metrics collection itself does not cause jank).Performance Metrics Service
App Startup Tracking
Usage in App Entry
APM Integration
Application Performance Monitoring (APM) tools give you a production-grade observability layer: automatic transaction tracing, error correlation, and dashboards that show how your app performs across device types, OS versions, and network conditions. If custom metrics are a thermometer, APM is a full medical workup. For most React Native teams, Sentry is the best starting point — it handles both crash reporting and performance monitoring in a single SDK, with excellent React Native support.Sentry Performance Monitoring
Custom Spans
New Relic Integration
Frame Rate Monitoring
Frame rate is the single most important performance metric for mobile apps. Anything below 60 FPS (16.67ms per frame) is perceptible as jank. Drops below 30 FPS feel genuinely broken. The hook below measures frame timing usingrequestAnimationFrame and classifies frames as “jank” when they exceed the 16.67ms budget.
This is a development tool — do not ship it in production builds, as the measurement itself consumes resources. Use APM tools for production frame rate tracking.
FPS Monitor Component
Memory Monitoring
Performance Dashboard
Choosing the Right Profiling Tool
Each tool in the profiling stack answers a different question. Using the wrong tool wastes time — you will see misleading data or miss the actual bottleneck entirely.
Decision framework — where to start:
- “The app feels slow” — Start with React DevTools Profiler. Most perceived slowness in React Native comes from unnecessary re-renders on the JS thread.
- “Animations are janky” — If the JS thread profiler shows renders completing under 16ms but animations still drop frames, the bottleneck is on the native thread. Switch to Xcode Instruments or Android Profiler.
- “Users report slowness but I can’t reproduce it” — You need production metrics. Set up APM (Sentry) and custom performance tracking to see what real users experience on real devices.
- “Startup takes too long” — Instrument startup milestones (JS load, first render, interactive). Compare against budgets: cold start under 2 seconds is the target; under 1 second is excellent.
- “The app crashes after extended use” — This is likely a memory leak. Use the Android Profiler’s memory timeline or Xcode’s Memory Graph to find retained objects.
Hermes vs. JSC Profiling Differences
If your app runs on Hermes (the default since React Native 0.70 and Expo SDK 48+), profiling behavior differs from JavaScriptCore (JSC) in important ways:
To take a Hermes CPU profile programmatically:
Performance Budgets
Defining concrete performance budgets turns vague “make it faster” requests into measurable, actionable targets. These budgets should be enforced in CI — not just aspirational numbers in a wiki.
Enforcing budgets in CI:
Common Profiling Pitfalls
Profiling in Development Mode
Development mode enables React’s reconciler warnings, Strict Mode double-renders, and disables most optimizations. Profiling in dev mode will show every component rendering 2x and taking 3-5x longer than production. Always profile release builds. For Expo:The Observer Effect
The act of profiling changes what you measure. Flipper adds network overhead. The React Profiler’sonRender callback adds JS thread work. The FPS monitor hook from this module uses requestAnimationFrame (which itself consumes frame budget). Profile with one tool at a time, and remove profiling instrumentation from production builds.
Misattributing Bridge Overhead
In the classic React Native architecture (pre-New Architecture), every communication between JS and native crosses the bridge asynchronously. This means a “slow render” might actually be a slow bridge crossing — the JS code finished fast, but the native update was queued behind other bridge traffic. With the New Architecture (Fabric + TurboModules), this is less of an issue because communication is synchronous. Check whether your app uses the New Architecture before spending time optimizing bridge traffic.Memory Leak False Positives
JS heap growing during a session does not always mean a leak. V8 and Hermes both use generational garbage collectors that may delay collection. A true leak is memory that grows monotonically and never decreases even after GC runs. To confirm: force GC (in Chrome DevTools attached to Hermes, click the trash can icon), then check if memory drops. If it does, you had garbage, not a leak.Best Practices
Profile in Production Mode
Development mode adds overhead - always profile release builds
Sample in Production
Don’t collect 100% of metrics in production - use sampling
Set Performance Budgets
Define acceptable thresholds and alert when exceeded
Monitor Real Users
Synthetic tests don’t capture real-world conditions
Production Sampling Strategy
Collecting metrics from every user session overwhelms your backend and inflates costs. Use tiered sampling:
Adjust these rates upward for smaller user bases. If you have under 10,000 DAU, sample at 100% for everything — the volume is manageable and you cannot afford to miss patterns.
Next Steps
Module 36: Error Handling & Crash Reporting
Learn to handle errors gracefully and report crashes effectively