In React Native, which tools capture native-side performance traces on iOS and on Android, and why doesn't React Native DevTools cover that?
answer
- one native profiler per platform
- Product > Profile opens Instruments
- Time Profiler samples every thread
- Capture System Activities, export to Perfetto
- DevTools is off in release builds
basics
~20 sXcode Instruments (usually the Time Profiler) on iOS and the Android Studio Profiler's system trace, viewable in Perfetto, on Android. React Native DevTools covers JavaScript and React only, and it is disabled in release builds.
solid answer
~40 sOn iOS I profile with Xcode Instruments: **Product > Profile** builds the app and opens Instruments, and the Time Profiler shows CPU time per thread — the main thread and React Native's JavaScript thread included. On Android I run the app as profileable on a real device and use the Android Studio Profiler's **Capture System Activities** task; the trace can be exported and opened in Perfetto. The standalone `systrace` tool is gone from platform-tools. React Native DevTools is built for JavaScript and React concerns — its own docs say it is not meant to replace native tools — and like the Dev Menu and LogBox it is disabled in release builds. So native tools answer *which thread* misses the frame; JavaScript tools then answer *which function or component*.
code
bash · 9 lines# Android: build a release variant to profile (bare project, Community CLI)
npx react-native run-android --mode release
# iOS: build the Release configuration (bare project, Community CLI)
npx react-native run-ios --mode Release
# Expo projects with native folders
npx expo run:android --variant release
npx expo run:ios --configuration Releasego deeper
Name one native profiler per platform: Instruments with the Time Profiler on iOS, the Android Studio Profiler's system trace on Android. Add that React Native DevTools does not run in release builds.
Explain what each tool can see: native tools show every thread against frame boundaries but only engine frames for JavaScript, while DevTools shows your functions and React tracks from a development build only.
Show the order you use them in: a native trace on a release-like build to find the saturated thread, then a JavaScript or React profile to find the cause, then a re-measure in release.
Discuss how a team makes profiling routine: which devices count as the low-end reference, when native traces are required in a performance review, and who owns keeping release-build profiling easy.
## Why React Native needs two kinds of profiler A React Native app is JavaScript running on the **JavaScript thread** inside the **Hermes** engine, driving **native views** that the platform lays out and draws on the **main (UI) thread** and, on Android, a separate **RenderThread**. A frame is on time only when all the work for it finishes inside the display's budget — about 16.7 ms at 60 Hz. A stutter can come from either side, so the tooling splits along the same line: - **JavaScript-side tools** — React Native DevTools — see your functions, React commits, network requests and user timings, but only the JavaScript side. - **Native-side tools** — Xcode Instruments on iOS, the Android Studio Profiler on Android — see every thread in the process: the main thread, the render thread, and the JavaScript thread as one more busy or idle row on the timeline. The React Native profiling guide opens with the same split: Instruments for iOS, the Android Studio Profiler for Android — and, before either, *make sure development mode is off*. ## iOS: Xcode Instruments **Instruments** is Apple's profiling suite. From Xcode, **Product > Profile** builds the app and opens Instruments; in a default scheme the Profile action builds the **Release** configuration, which is what you want before trusting any number. The template most React Native investigations start with is the **Time Profiler**, which samples the call stacks of all threads and shows where CPU time goes. What to look for in the recording: - the **main thread** — native layout, view creation and drawing; - the React Native **JavaScript thread** — in the New Architecture runtime it is named `com.facebook.react.runtime.JavaScript`; - how to narrow the stacks — call-tree options such as *Hide System Libraries* and *Invert Call Tree* bring your own frames to the top. A native profiler sees the JavaScript thread as **engine frames**, not your function names. It tells you *that* JavaScript is the bottleneck; a JavaScript profile tells you *where*. ## Android: the Android Studio Profiler, then Perfetto The profiling guide notes that the standalone `systrace` tool has been **removed** from Android platform-tools; the Android Studio Profiler replaces it. 1. Connect a **physical device** that shows the problem over USB. 2. Open the project's `android` folder in Android Studio and **run the app as profileable** — the profiler attaches with low overhead — ideally from the release variant, so the JavaScript is not in dev mode either. 3. Bring the app to just before the interaction, start the **Capture System Activities** task, perform the interaction, then press *Stop recording*. 4. Inspect the trace in Android Studio, or pick it in *Past Recordings*, press *Export recording*, and open it in **Perfetto**. In the trace you find the **UI thread** (named after your package), the **JavaScript thread** (`mqt_v_js` in the New Architecture runtime) and **RenderThread**, laid against the frame boundaries. For native CPU detail there is also *Find CPU Hotspots (Java/Kotlin Method Recording)*, which is slow and only gives proportions, not accurate timings. ## Where React Native DevTools fits — and where it stops React Native DevTools replaced Flipper and remote JS debugging as React Native's debugger, and since 0.83 it has a Performance panel. Its docs are explicit that it is designed for React app concerns, **not to replace native tools**. Two limits follow: - It shows JavaScript execution, React tracks, network events and user timings — not native layout, drawing or GPU work. - The Dev Menu, LogBox and React Native DevTools are **disabled in release builds**, so DevTools only ever watches a development build, whose JavaScript runs in dev mode. ## Picking the tool for the question | Question you are asking | Tool | |---|---| | Which thread misses the frame on iOS? | Instruments, Time Profiler | | Which thread misses the frame on Android? | Android Studio system trace, opened in Perfetto if you like | | Which JavaScript function is hot? | a Hermes sampling profile, recorded through React Native DevTools | | Which React component committed slowly? | the React DevTools Profiler | | Did a fix hold in a release build? | `performance.mark` / `performance.measure`, read with `PerformanceObserver` | ## Common mistakes - **Profiling on a simulator or emulator.** They run on desktop hardware, so frame timings do not match a phone; the guide says to connect a device that shows the stutter. - **Reaching for Flipper.** It is no longer part of React Native's tooling; React Native DevTools replaced it for JavaScript, and the platform profilers cover native work. - **Dismissing native traces "because the app is JavaScript".** They are the only view that shows whether the JavaScript thread or the UI thread is the one running past the frame boundary — the first fork in every jank investigation.
- Why run the Android app as profileable when capturing a React Native system trace?A debuggable build carries extra runtime overhead, and a React Native debug build also runs development-mode JavaScript from Metro. A profileable build lets the Android Studio Profiler attach to a release-like build with low overhead, so the trace shows the timings users actually get rather than the cost of debugging.
- In an Instruments Time Profiler recording of a React Native iOS app, how do you tell JavaScript work from native UI work?Filter the call tree by thread. The main thread carries native layout, view creation and drawing; the JavaScript thread, named `com.facebook.react.runtime.JavaScript` in the New Architecture runtime, carries Hermes execution. If the JavaScript thread is saturated during the stutter, switch to a JavaScript profile to find the function, because Instruments shows engine frames, not your code.
saying these in an interview costs you the question
- React Native DevTools shows main-thread layout and GPU work
- Flipper is still the tool for React Native performance profiling
- Run the standalone systrace tool to capture Android traces
- Native profilers are useless because React Native app code is JavaScript
- Simulator and emulator frame times are representative of a phone