This tool works with both Expo and React Native CLI projects. Just install and go.
Measure and prove performance on a real device. Bench tracks UI FPS, JS FPS, CPU, memory, and jank in real time, records runs you can save and compare, and can benchmark a matrix of variants to tell you which implementation is actually faster.
Walk the live tour: the HUD streams → FlatList janks → open the run for render blame → a ranked batch crowns FlashList → the library keeps the proof.
Not a video — this is the shipped Bench tool on mock data. JS FPS, UI FPS, CPU, and memory stream while you navigate /products.
Bench relies on native peers. Install the package with Reanimated and Worklets (required), plus the performance toolkit and Nitro modules that power true native UI-thread metrics:
npm install @buoy-gg/perf-monitor react-native-reanimated react-native-worklets react-native-performance-toolkit react-native-nitro-modulesThese ship native code, so rebuild the app with a custom dev build (expo prebuild then npx expo run:ios / run:android) — not Expo Go — and run pod install on iOS. See Reanimated's setup for its Babel plugin. Without react-native-performance-toolkit, Bench still runs in JS-only mode; adding it unlocks native UI FPS and CPU.
Once installed, Bench appears in the floating menu. On Buoy Desktop it also renders as a live HUD you can watch while you use the app.
Bench also runs in the browser — Expo web, Electron, or any React DOM app — with no native modules and no dev build. On web the HUD samples browser APIs instead:
React Native Web apps get this automatically. Plain React apps need the standard one-line bundler alias (react-native → react-native-web) and can render the HUD directly:
import { PerfMonitorOverlay, PerfMonitorController } from "@buoy-gg/perf-monitor";
// anywhere in your tree
<PerfMonitorOverlay />
// toggle it
PerfMonitorController.toggle();
import { PerfMonitorOverlay, PerfMonitorController } from "@buoy-gg/perf-monitor";
// anywhere in your tree
<PerfMonitorOverlay />
// toggle it
PerfMonitorController.toggle();
The sampler runs on the JS thread, so it physically can't take samples while the JS thread is blocked. Instead of silently skipping those moments (which would make stalls invisible in recordings and on the desktop dashboard's live HUD), the monitor detects the gap when sampling resumes and backfills it with reconstructed 0 JS FPS samples — so history sparklines, live sync, and saved reports all show the stall. Reconstructed samples are marked synthetic in report JSON, counted in the report's stats, and never fabricated across app backgrounding. One consequence worth knowing: recordings made before this behavior existed under-report JS stalls, so a stall-heavy run recorded today will (honestly) score worse than the same behavior recorded on an older version.
With @buoy-gg/highlight-updates installed, every recording — manual or batch — also captures which components rendered, how many times, and how long they took (self time, React DevTools profiler convention). Batch reports gain a Top re-renderers section per case, single-run reports get a Render commits block, and the MCP run_benchmark_batch ranking includes the heaviest components per case — so instead of "case B dropped to 41 JS FPS" you get "case B dropped to 41 JS FPS because ProductList rendered 47× costing 312ms".
A few things to know:
Bench powers Buoy's AI performance workflow. The MCP server ships a buoy-optimize wizard skill that turns the whole tune → measure → repeat loop into an almost hands-off process. Point your assistant at a new feature you're building — or an existing screen that's slow on device — and it will:
Because it measures on-device instead of guessing, it collapses what is normally days or weeks of AI back-and-forth into minutes. In one real pass, a Skia LED display went from 28 lights stuttering under advanced effects to over 12,000 lights with no lag.
The only steps that stay manual are the ones a human has to eyeball — mainly confirming the result still renders correctly. If you're on Skia or other GPU-drawn UI, plan to glance at the screen between passes: the wizard drives the metrics, you verify it still looks right. Say "buoy optimize" in your editor to start.
Looking for an overview with screenshots and FAQs? See the Bench — Performance Monitor page on buoy.gg.