Performance tab
Statistics cards, user timing, interactions and long tasks.
The toolbar carries the record button, the clear button, then the section chips:
[⏺] [⊘] │ (Statistics) (User timing) (Interactions) (Long tasks)Only the chosen section is mounted, which is deliberate: the charts stop re-rendering while you read a list, and a burst of long tasks does not re-render a chart. The three list chips carry a live count when they have entries.
This tab starts paused (performance.disabledByDefault defaults to true) because measuring costs
something. While paused the collectors are detached rather than left running and filtered, so a paused
tab costs nothing at all; pressing record attaches them fresh and re-reads whatever the platform still
has buffered. Every empty list shows the same Not recording panel with a Start recording button.
performance.historySize (default 120) caps the memory samples, long tasks, user timing entries and
interactions kept.
Statistics
Four cards plus the startup breakdown.
Frames per second
| Field | Meaning |
|---|---|
| JS thread | Current frames per second from a requestAnimationFrame delta loop, sampled every 500 ms. |
| Main thread | Current frames per second from a native display-link counter. Reads dev build without the native module. |
| Chart | Both threads on one plot, one colour per thread, 60 buckets of 5 s, covering the last 5 min. Each bucket keeps its worst reading. |
| Axis | Scaled to the confirmed peak (min 60) plus headroom, so a 120 Hz device is not clipped. |
The gap between the two lines is the reading that matters: a healthy JS line above a collapsed main line is an app that feels frozen while every JS metric says it is fine.
Interactions card
The slowest event-to-next-paint seen, with the average and the count as the hint. Before anything is
captured it reads Slowest event to next paint.
Memory
| Field | Meaning |
|---|---|
| JS Heap plot | performance.memory used heap, captioned of <total> allocated. Reads This JS engine doesn't report it on JSC/V8. |
| App memory plot | Whole-process footprint, what the OS holds against you. Needs a dev build. |
| Device memory meter | Used against total RAM, captioned with what is still available to this app. On Android that is system-wide free memory; on iOS it is what the process can still claim. Needs a dev build. |
Both plots are sampled on performance.sampleIntervalMs (default 1 s) and span historySize samples,
two minutes at the defaults. Each carries its own peak marker.
Storage
Disk space, not the Storage tab's contents — a Used meter against the data partition's total, captioned with the free space. Android only, and needs a dev build; the card says which of the two is missing.
iOS is absent on purpose: systemFreeSize is one of Apple's required-reason APIs, and a library reading
it would push a privacy-manifest declaration onto every app that embeds it.
Startup
Process start to first render, read once at launch. Up to two blocks:
| Block | Rows |
|---|---|
| Measured by this package | Total · Native startup · Bundle eval · App setup · To first render |
| Reported by the platform | Total · Native init · Runtime setup · Bundle eval |
The measured block comes from the native module's real process start time, so it works where the
platform's own markers are all null. Its phase boundaries are this package's own load points, so they
shift a little with your import order; the earlier you call .init(), the truer App setup is. The
platform block is performance.rnStartupTiming, and a dash means the platform never reported that
marker. The whole section is hidden when neither is available.
User timing
Marks and measures you record yourself, newest first.
| Column | Meaning |
|---|---|
| Name | The name you passed. |
| Kind | An icon, not a word: a pin for a mark, a ruler for a measure. |
| Detail | Your detail, stringified, when you passed one. |
| Time | Wall-clock time it was recorded. |
| Duration | The measured span; a mark shows —. |
This is the only list here that can point at a specific piece of your code, which makes it the answer to
a long task you cannot explain. See mark and measure.
Interactions
Anything slower than performance.interactionThresholdMs (default 100 ms) from event to next paint.
| Column | Meaning |
|---|---|
| Name | The event type. |
| handler Xms | How long your handler itself held the JS thread. |
| Duration | Event to next paint, colour-coded by severity. |
A small handler under a large total means the interaction was stuck behind something else rather than being slow itself. The platform rounds durations to 8 ms and never reports anything under 16 ms.
Long tasks
Stretches of JavaScript that ran without yielding for longer than
performance.longTaskThresholdMs (default 150 ms), newest first: name, wall-clock time, and
duration colour-coded by severity. At 60 fps a frame is 16.7 ms, so 150 ms is about nine frames lost;
past roughly 200 ms it reads as a freeze.
A long task tells you when to look, never at what: React Native's PerformanceLongTaskTiming returns
a permanently empty attribution array. Correlate against what the app was doing, or wrap the suspect
in mark and measure.
Both this list and Interactions show a note when the platform's own buffer overflowed and discarded entries before the panel could read them.