skip to content

How do you turn on Flutter's PerformanceOverlay on a running app, and what do its two graphs tell you?

level: juniorimportance: should knowfreq 42%

answer

  1. showPerformanceOverlay on MaterialApp
  2. P in flutter run, or a DevTools button
  3. top graph raster, bottom graph UI
  4. lines mark frame-budget steps
  5. red bar: that thread missed

basics

~20 s

Set showPerformanceOverlay: true on MaterialApp, press P in a flutter run session, or use DevTools' Performance Overlay button. The engine draws two graphs over the app: raster time on top and UI time below, with red bars for frames that missed the budget.

solid answer

~40 s

`PerformanceOverlay` is a widget the engine paints directly. The easy ways to show it are `MaterialApp(showPerformanceOverlay: true)` (also on `WidgetsApp`, default `false`), pressing **P** in the terminal running `flutter run`, or the **Performance Overlay** button in DevTools' performance view. It shows two graphs over your UI: the **top** graph is the **raster** thread and the **bottom** graph is the **UI** thread, each covering recent frames. Horizontal lines mark 16 ms steps. A frame that exceeds the budget draws a **red** vertical bar in the graph of the thread that missed. A red bar in the UI graph means Dart work is too expensive; in the raster graph, the scene is too costly to draw. Use it in profile mode, since debug numbers are misleading.

code

dart · 10 lines
dart
import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      showPerformanceOverlay: true,
      home: Scaffold(body: Center(child: Text('Scroll and watch the graphs'))),
    ),
  );
}

go deeper

for a junior

Know the three ways to show the overlay and that the top graph is raster, the bottom is UI, and red means a missed frame.

for a middle

Explain what a red bar in each graph implies about the cause, and why the overlay must be read in profile mode.

for a senior

Use the overlay for a quick live read on a device, then move to the DevTools timeline to find the responsible widgets.

for a principal

Decide when testers should run overlay builds and how their observations feed into the team's performance process.

## What the overlay is **`PerformanceOverlay`** is a `LeafRenderObjectWidget` whose render object asks the engine to draw frame statistics over your app. The engine paints it, not your widget tree, so it costs very little and does not distort the numbers it shows. The Flutter docs describe each graph as showing the last 300 frames for its thread. ## Three ways to turn it on 1. **In code.** `MaterialApp(showPerformanceOverlay: true, ...)`. The same flag exists on `WidgetsApp` and `CupertinoApp`, and it defaults to `false`. Use it for a build you hand to a tester. 2. **From the terminal.** Press **P** in the terminal session running `flutter run` to toggle it on the attached app. 3. **From DevTools.** Click **Performance Overlay** in the performance view. You can also place `PerformanceOverlay.allEnabled()` in the tree yourself, or `PerformanceOverlay(optionsMask: ...)` built from `PerformanceOverlayOption` values, to choose which statistics appear. `allEnabled()` is not a `const` constructor, because it computes the mask. ## Reading the two graphs | Graph | Thread | Red bar means | |---|---|---| | top (marked GPU in the docs) | raster: turns the layer tree into GPU commands | the scene was too expensive to draw in time | | bottom | UI: your Dart code and the framework's build, layout and paint | Dart work for that frame took too long | - The **horizontal axis** is frames. The graph only advances when the app paints, so an idle app shows a still graph. - The **vertical axis** is time. White lines mark 16 ms steps; a bar above the first line ran slower than 60 Hz. - **Green** vertical bars mark the current frame when things are fine. **Red** bars appear in the graph of the thread that missed its budget. - When **both** graphs show red, the docs advise diagnosing the UI thread first. ## Choosing statistics with optionsMask `PerformanceOverlay(optionsMask: ...)` takes a bit mask built by shifting 1 by the index of each **`PerformanceOverlayOption`** you want: - `displayRasterizerStatistics`: raster frame time and FPS as text; - `visualizeRasterizerStatistics`: the raster graph; - `displayEngineStatistics`: UI frame time and FPS as text; - `visualizeEngineStatistics`: the UI graph. `PerformanceOverlay.allEnabled()` sets all four. For example, `1 << PerformanceOverlayOption.visualizeRasterizerStatistics.index` shows only the raster graph, which is handy when you are tuning a raster-heavy screen and want less clutter. ## Why profile mode matters here The docs say the overlay should always be viewed in **profile mode**. Debug builds run JIT-compiled code with assertions and extra checks, so the UI graph shows red bars that release builds would never have. Profile builds are compiled like release builds but keep enough tracing to measure. Run on a physical device too, because an emulator's GPU has nothing in common with a phone's. ## When to reach for it and when not to - **Good for:** watching a scroll or an animation live on a device, showing a tester where jank happens, and seeing at a glance which thread is struggling. - **Not enough for:** finding which widget or render object is responsible. For that, record the same interaction in the DevTools performance view, select the red frame and read its timeline events. - **Not for users:** leave `showPerformanceOverlay` off in shipped builds. To measure real users, collect `FrameTiming` data with `SchedulerBinding.instance.addTimingsCallback` instead. ## A typical first session Turn on the overlay, open the slow screen and repeat the interaction a few times. If only the bottom graph spikes, look at build and layout work. If only the top graph spikes, look at what the screen draws: translucency, clips, shadows and large images. Then move to DevTools for the detail.

  • Does turning on the PerformanceOverlay itself slow the app down?
    Very little. The Flutter docs note that the graphs are not drawn like a normal widget: the engine paints the overlay itself and only minimally affects performance. That is why it is safe to leave on during a profiling session, unlike tracing options that add timeline events and do inflate frame times.
  • The overlay shows red bars only in the bottom graph while scrolling a list. What does that suggest?
    The UI thread is over budget, so the Dart side of each frame is too expensive: items rebuilding or laying out too much, work done in `build`, or synchronous computation during scroll. The raster side keeps up. Record the scroll in DevTools and check build and layout events for the list items.

saying these in an interview costs you the question

  • The top graph shows UI thread time and the bottom shows raster time
  • The overlay is a debug-mode-only feature
  • A red bar in the raster graph means the Dart code is too slow
  • The PerformanceOverlay shows which widget caused a slow frame
  • The overlay's own drawing cost makes its numbers unreliable