← Articles

Flutter DevTools: profiling your app step by step

By John · 11 February 2025

Flutter DevTools is the official debugging and performance suite for Flutter. It runs in the browser and connects to a running Flutter app via VM service. Most developers underuse it — it's the fastest way to diagnose jank, memory leaks, and widget tree bloat.

Opening DevTools

flutter run
# DevTools URL is printed:
# http://127.0.0.1:8181/...

In VS Code: F5 to run, then open DevTools via the Flutter sidebar. In Android Studio: View → Tool Windows → Flutter Inspector.

Performance tab: finding jank

Jank occurs when frames take longer than 16.67ms (60 FPS). The Performance tab shows a frame timeline.

  1. Trigger the janky scroll/animation
  2. Click Record
  3. Reproduce the jank
  4. Click Stop → see the frame timeline

Red frames = over budget. Click a red frame for its flame chart. Wide blocks = lots of time. Look for build, layout, and paint taking > 2ms each.

Widget Inspector

Shows the entire widget tree of the running app.

Find unnecessary rebuilds: Select "Track widget builds" then interact with the app. Rebuilt widgets highlight. If Column or Container rebuilds every frame, you're missing const constructors or RepaintBoundary.

Inspect a widget: Tap "Select Widget Mode" then click a widget in the app. The right panel shows render properties, constraints, and size.

Memory tab: finding leaks

Common sources of memory leaks:

  • Animation controllers not disposed
  • Stream subscriptions not cancelled
  • ScrollController not disposed

Workflow:

  1. Memory tab → click Monitor
  2. Navigate through screens
  3. Navigate back to start
  4. Click GC → take a heap snapshot

If memory grows after returning to the starting screen, you have a leak. Search the snapshot for your widget's state class name.

Fix:

class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
  }

  @override
  void dispose() {
    _controller.dispose(); // REQUIRED
    super.dispose();
  }
}

Network tab

Shows all HTTP requests (works with Dio automatically). Use it to:

  • Inspect request/response bodies and headers
  • Find slow requests
  • Debug auth header issues

Logging tab

Shows print(), debugPrint(), and framework log messages. Better than the terminal — filter by level, search, and see timestamps.

App Size analysis

flutter build apk --analyze-size
flutter build ios --analyze-size

Loads into DevTools → App Size as a treemap. Common findings: Firebase and Google Maps are large. The Flutter engine itself is ~5-7MB and unavoidable.

CPU Profiler

For non-UI performance (slow JSON parsing, compute-heavy operations):

  1. CPU Profiler → Start recording
  2. Trigger the slow operation
  3. Stop → see where time was spent

Heavy processing on the main thread causes jank. Move it to an isolate:

final result = await compute(parseOrders, rawJson);

Always profile in profile mode

Debug mode is 2-5x slower. Always use --profile for performance work:

flutter run --profile

Performance overlay

For quick in-app monitoring:

MaterialApp(
  showPerformanceOverlay: true,
)

RepaintBoundary

Animating one widget repaints its entire parent subtree. Wrap animated widgets to isolate repaints:

RepaintBoundary(
  child: AnimatedWidget(...),
)

Common pitfalls

Profiling in debug mode. Debug overhead masks real performance costs. Always use --profile.

Ignoring the Widget Inspector. It shows which widgets rebuild and why — essential for performance, not just layout debugging.

Not setting up a RepaintBoundary. Without it, a 60 FPS animation can trigger expensive repaints of large parts of the tree on every frame.

Sign in to like, dislike, or report.

Flutter DevTools: profiling your app step by step — ANN Tech