skip to content

Dev Loop & DevTools

The development-time toolbox: hot reload, debug versus profile and release builds, the widget inspector, memory snapshots, logging and error hooks. Interviewers use it to spot real debugging practice.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

30

What are Flutter's debug, profile and release build modes, and when do you use each one?

level: juniorimportance: must knowfreq 72%

answer

  1. develop, measure, ship
  2. asserts only in debug
  3. profile: AOT plus tracing
  4. release: no service extensions
  5. flutter run defaults to debug

basics

~20 s

Debug mode is for development: asserts, service extensions, a debugger and hot reload, but slow. Profile mode is AOT-compiled like release with tracing so you can measure performance on a device. Release mode is optimized, with asserts and debugging off, for users.

solid answer

~40 s

`flutter run` builds in **debug** mode by default: code runs in the Dart VM with JIT, assertions are on, all service extensions and the debugger are available, and hot reload works, but performance is not representative. **Profile** mode (`--profile`) compiles ahead of time like release, but keeps tracing, a DevTools connection and a few service extensions such as the performance overlay; it runs on real devices, not the iOS Simulator. **Release** mode (`--release`, and the default for `flutter build` targets) turns off assertions, service extensions and debugging, and optimizes for start-up, speed and size. Use debug to develop, profile to measure, release to ship.

code

bash · 9 lines
bash
# Debug (default): asserts, service extensions, hot reload
flutter run

# Profile: AOT with tracing, on a physical device
flutter run --profile

# Release: what users get
flutter run --release
flutter build apk        # release by default

go deeper

for a junior

Know what each mode is for and that flutter run starts in debug while flutter build defaults to release.

for a middle

Explain the concrete differences: JIT versus AOT, asserts, service extensions, debugger access and where each mode can run.

for a senior

Show the habit of profiling on real devices and smoke-testing release builds, because some failures appear only in that mode.

for a principal

Set the team's rules for which mode QA, performance budgets and release candidates use, so results are comparable across builds.

## Three modes for three jobs The Flutter tool compiles an app in one of three **build modes**, chosen by where you are in the development cycle. The Flutter docs summarise it in one line each: **debug** while developing and using hot reload, **profile** when analysing performance, **release** when shipping. (A fourth, headless test mode is what `flutter test` uses; it behaves like debug.) | | Debug | Profile | Release | |---|---|---|---| | Mobile compilation | JIT-run kernel code, built for fast edit cycles | AOT machine code | AOT machine code | | Assertions | **On** | Off | Off | | Service extensions | All | Some (for example the performance overlay) | **None** | | Debugger and DevTools | Full source-level debugging | Tracing and DevTools connection | Disabled | | Hot reload and restart | Yes | No | No | | Runs on iOS Simulator | Yes | No | No | | Typical command | `flutter run` | `flutter run --profile` | `flutter run --release`, `flutter build <target>` | ## Debug mode Debug is the default for `flutter run`. It is tuned for **fast development cycles**, not for speed or size: - Dart **`assert`** statements run, and the framework itself is full of them, catching layout and state mistakes early. - **All service extensions** are registered, so DevTools can toggle debug painting, open the widget inspector and so on. - A debugger can connect, set breakpoints and step through code. - **Hot reload** works only here, because it needs the JIT-capable VM and the debug connection. - The top-right **DEBUG banner** from `WidgetsApp.debugShowCheckedModeBanner` appears only in debug builds. The cost is performance: the docs warn that apps can be janky in debug mode, so its timings mean little. ## Profile mode Profile mode is **release-like compilation with just enough instrumentation to measure**. On mobile it matches release except that tracing is on, DevTools can connect, and a few service extensions stay available, such as the one that turns on the performance overlay. Profile mode is not available on the iOS Simulator; the docs say emulators and simulators do not represent real performance, so profile on a physical device. ## Release mode Release mode is what users install. Assertions are **off**, debugging information is stripped, debugging and service extensions are **disabled**, and compilation targets fast start-up, fast execution and small packages. `flutter build apk` and `flutter build ios` produce release builds by default, while `flutter run` defaults to debug. ## On the web The modes map to different compilers on the web: - **Debug**: compiled with the development compiler (`dartdevc`), not minified or tree-shaken. - **Profile**: compiled with `dart2js`, tree-shaken but not minified; DevTools cannot connect, so use the browser's own performance tools. - **Release**: compiled with `dart2js`, minified and tree-shaken. ## Choosing in practice 1. Writing features and fixing bugs: **debug**. 2. Checking whether a screen is smooth, or how long start-up takes: **profile**, on a real device. 3. QA passes, store builds, and anything a user sees: **release**. A useful habit is to run a release build on a real device before every release candidate, because some behaviour differs only there: assertions disappear, debug-only code is compiled out, and platform configuration can differ between build variants. ## Misconceptions interviewers listen for - **"Profile is debug with DevTools."** No: profile is compiled ahead of time like release; it keeps tracing, not assertions or hot reload. - **"Release is just faster debug."** Release removes assertions, debug-gated code and service extensions, so it can behave differently, not only faster. - **"The emulator is fine for timing."** The docs recommend measuring on an actual device; the iOS Simulator cannot even run a profile build. - **"`flutter build` gives me what I tested."** It defaults to release, while `flutter run` defaults to debug, so the build you tested and the build you ship may be different modes unless you pass the flag deliberately.

  • Why can't you run a profile build on the iOS Simulator?
    The Flutter tool only accepts debug builds for the iOS Simulator. The docs explain that simulators and emulators do not represent real device performance, so profiling there would give misleading numbers; profile on a physical device.
  • Which build mode does flutter build apk produce if you pass no flag?
    Release. The `flutter build` targets add the `--debug`, `--profile` and `--release` flags with release as the default, while `flutter run` defaults to debug.

Debug is a car on the workshop lift with the panels off and every gauge attached; profile is the finished car with a data logger on the test track; release is the car in the customer's garage with the logger removed.

saying these in an interview costs you the question

  • Profile mode is just debug mode with DevTools attached.
  • Release builds still evaluate assert statements.
  • Hot reload also works on a profile build.
  • flutter build apk produces a debug APK unless told otherwise.
  • Debug-mode frame times are close enough to judge smoothness.
open as a page

In Flutter, what is the difference between hot reload, hot restart and a full restart, and when do you need each?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Hot reload injects changed Dart code and rebuilds widgets while keeping state; hot restart reloads the code and reruns main(), losing state; a full restart rebuilds native code too and is needed after Kotlin, Swift or plugin changes.

open as a page

In Flutter DevTools, how do you use the Widget Inspector's Select Widget Mode to find which widget draws a given element on screen?

level: juniorimportance: must knowfreq 55%

basics

~20 s

Turn on Select Widget Mode in the DevTools Flutter inspector and tap the element in the running debug app; the inspector selects that widget, scrolls the widget tree to it, and shows its size, constraints and properties in the Widget Explorer.

open as a page

In Flutter, what is the difference between print() and debugPrint(), and why does debugPrint exist at all?

level: juniorimportance: must knowfreq 55%

basics

~20 s

print() writes each message straight to the console. debugPrint() is Flutter's throttled wrapper: it queues lines and releases about 12 KB of text, then pauses a second, so Android does not drop log lines. Both still print in release builds.

open as a page

Why should a Flutter team never judge a janky screen's performance in debug mode, and what should they do instead?

level: middleimportance: must knowfreq 60%

basics

~20 s

Debug builds run JIT-compiled code with assertions and debug-only work on every frame, so their timings are unrepresentative and unevenly distorted. Reproduce the jank with flutter run --profile on a physical device, then measure and optimize there.

open as a page

In Flutter, which errors reach FlutterError.onError and which reach PlatformDispatcher.instance.onError, and why does an app need both?

level: middleimportance: must knowfreq 58%

basics

~20 s

FlutterError.onError receives errors the framework catches inside its own callbacks: build, layout, paint, gesture handlers. PlatformDispatcher.instance.onError receives uncaught errors with no Flutter callback on the stack, such as a failed await in an async onPressed. Reporting needs both.

open as a page

In Flutter, why does a hot reload not show your change to main(), initState() or a static field's initializer?

level: middleimportance: must knowfreq 52%

basics

~20 s

Hot reload swaps in new code but only reruns build methods. main() and existing initState() calls already ran, and global and static fields keep their stored values as state, so those edits need a hot restart, a const field or a getter.

open as a page

In a Flutter app, which undisposed controllers, listeners and stream subscriptions actually leak memory, and why do they leak?

level: middleimportance: must knowfreq 55%

basics

~20 s

They leak when something longer-lived still reaches them: a subscription on a service's stream, a listener added to a global ChangeNotifier, a running AnimationController's ticker or a periodic Timer. Their callbacks capture the State, so the closed screen's State and subtree stay alive.

open as a page

In Flutter, what is the red error screen, and what does a release-build user see when the same widget's build method throws?

level: juniorimportance: should knowfreq 52%

basics

~20 s

The red screen is an ErrorWidget built in place of a widget whose build threw. Debug builds show the exception in yellow on red; profile and release builds, with asserts off, show a plain grey box with no text.

open as a page

In Flutter DevTools, what do the memory view's Profile Memory, Diff Snapshots and Trace Instances tabs each help you find?

level: juniorimportance: should knowfreq 35%

basics

~20 s

Profile Memory lists current allocation by class; Diff Snapshots compares heap snapshots taken before and after an interaction to show which classes grew and what retains them; Trace Instances records the call stacks that allocate the classes you select.

open as a page

In Flutter, what are kDebugMode, kProfileMode and kReleaseMode, and when would you use assert instead?

level: middleimportance: should knowfreq 40%

basics

~10 s

They are const booleans from package:flutter/foundation.dart telling which mode the app was compiled in, so gated code is removed elsewhere. Prefer kDebugMode for debug-only code and assert for invariants; asserts run only in debug.

open as a page

When a Flutter app replaces FlutterError.onError, why should the handler still call FlutterError.presentError, and what does FlutterErrorDetails carry?

level: middleimportance: should knowfreq 30%

basics

~20 s

FlutterError.onError defaults to presentError, which prints the error and is the hook the IDE's structured error view replaces. A custom handler that skips presentError loses that output. FlutterErrorDetails carries the exception, stack, library, context, an information collector and a silent flag.

open as a page

Which Flutter code changes does hot reload reject or fail to apply, and what do you do instead for each?

level: middleimportance: should knowfreq 32%

basics

~20 s

Hot reload rejects turning an enum into a class or back and changing a class's generic type parameters, so hot restart. It cannot see native Kotlin or Swift edits or new platform plugins, which need a full restart, and it waits for compile errors to be fixed.

open as a page

In Flutter, what is the difference between debugDumpApp() and debugDumpRenderTree(), and when would you reach for each?

level: middleimportance: should knowfreq 30%

basics

~20 s

debugDumpApp() prints the widget-level tree from the root element, with dirty flags, dependencies and state; debugDumpRenderTree() prints each render tree with constraints, sizes and parent data. Use the first for what was built, the second for why something has its size.

open as a page

In Flutter, what does setting debugPaintSizeEnabled to true draw on screen, and how do you switch it on during a debug session?

level: middleimportance: should knowfreq 40%

basics

~20 s

debugPaintSizeEnabled, a top-level bool in package:flutter/rendering.dart that defaults to false, makes every RenderBox paint its bounds, with padding shaded and alignment offsets drawn as arrows. Set it before runApp, press p in flutter run, or use the inspector's Show guidelines.

open as a page

In Flutter DevTools, how does the inspector's flex explorer help you diagnose an overflowing Row, and what happens to edits you make there?

level: middleimportance: should knowfreq 35%

basics

~20 s

Selecting a Row, Column or Flex, or a direct child, shows the flex explorer: axes, alignments, flex factors and constraints, with overflow in yellow-and-black tape. Edits to alignment or flex apply live, never touch source and revert on hot reload.

open as a page

In Flutter, how do you set breakpoints and step through code with the DevTools debugger, and what does dart:developer's debugger() add?

level: middleimportance: should knowfreq 40%

basics

~20 s

Click the line-number gutter in the DevTools Debugger or your IDE to set a breakpoint, then read the call stack and variables and step in, over or out. dart:developer's debugger(when: condition) is a code-level breakpoint that pauses only when true.

open as a page

In Flutter, what does log() from dart:developer give you over print(), and how do you read its output in DevTools?

level: middleimportance: should knowfreq 40%

basics

~20 s

log() from dart:developer emits a structured event with a name, a severity level (0-2000, default 0) and an optional error and stack trace, sent to attached tools. The DevTools Logging view lists and filters these events.

open as a page

In Flutter, what is the Dart VM service, and what does the DevTools network view record through it?

level: middleimportance: should knowfreq 30%

basics

~20 s

The Dart VM service is the tooling protocol a debug or profile Flutter app exposes; flutter run prints its URL. Through it, the DevTools network view records HTTP, HTTPS and WebSocket traffic from dart:io (dio included) and http_profile clients.

open as a page

In Flutter, why can a closure that captures BuildContext leak memory, and how do you write the same code without the leak?

level: middleimportance: should knowfreq 40%

basics

~20 s

A BuildContext is the widget's Element, which reaches its State and subtree. A closure capturing it, handed to a longer-lived object, keeps that whole subtree alive. Read what you need first (final theme = Theme.of(context)) and capture that value, or unregister the closure in dispose.

open as a page

A Flutter app works in debug but fails only in a release build on Android; which build-mode differences do you check first?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Check what differs in release: the Android template declares INTERNET only in the debug and profile manifests, asserts and kDebugMode code are compiled out, service extensions are gone, and code is AOT-compiled. Reproducing in profile narrows which difference it is.

open as a page

Users of a Flutter release build see a grey box where a crashed widget should be, yet the crash reporter shows nothing; what is missing, and how do you fix it?

level: seniorimportance: should knowfreq 38%

basics

~20 s

The grey box means the framework caught a build exception and sent it to FlutterError.onError, whose default only prints. Reporting wired only to uncaught errors never sees it; forward FlutterError.onError to the reporter, then fix the build.

open as a page

A bug shows up in a Flutter debug session after several hot reloads but not after a hot restart; how do you tell a reload artefact from a real bug?

level: seniorimportance: should knowfreq 24%

basics

~20 s

Hot reload runs new code on state created by old code, so objects, statics and initState setup can be impossible combinations. Hot restart and reproduce from launch: if the bug is gone, it was a reload artefact; if it persists, it is real.

open as a page

A Flutter settings page shows an unexpected gap beside one ListTile's text; how would you use the inspector to find which widget adds that padding?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Turn on Show guidelines to see the padding, tap the gap in Select Widget Mode, enable Show implementation widgets to reveal the ListTile's internal Padding, then fix the value where it is owned: the tile, ListTileThemeData or an ancestor.

open as a page

A Flutter checkout's payment-success callback sometimes fires twice; how would you trace why with logging, breakpoints and DevTools?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Log each call with a name and sequence number, pause on the second call with a conditional breakpoint or debugger(when:) and compare its call stack with the first, and count requests in the network view. Usually a listener was registered twice.

open as a page

Memory in a Flutter app grows every time users open and close the chat screen; how would you find and confirm the leak with DevTools?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Snapshot at the chat list, open and close the chat N times, snapshot again and diff; classes growing by N, such as the chat State, are the leak. Their retaining path names the long-lived holder, typically an uncancelled subscription or listener. Fix it and re-diff.

open as a page

In Flutter, what does leak_tracker detect, and how do you enable it so testWidgets fails on undisposed objects?

level: seniorimportance: should knowfreq 25%

basics

~20 s

leak_tracker watches instrumented disposables and reports not-disposed leaks (collected without dispose), plus experimental not-GCed and GCed-late leaks. Add leak_tracker_flutter_testing as a dev dependency and call LeakTesting.enable() in test/flutter_test_config.dart; testWidgets then fails the file on leaks.

open as a page

In Flutter, what are service extensions, and why are some available in profile mode but none in release?

level: middleimportance: nice to knowfreq 15%

basics

~20 s

Service extensions are named hooks the app registers with the Dart VM service so DevTools and the flutter tool can query or toggle it. Debug registers all, profile keeps measurement ones such as the performance overlay, and release registers none.

open as a page

How does hot reload work for a Flutter web app in Flutter 3.47, and how does it differ from mobile?

level: middleimportance: nice to knowfreq 20%

basics

~20 s

Since Flutter 3.35 hot reload is on by default for web debug builds, alongside hot restart. It loads updated DDC-compiled JavaScript into the page instead of a Dart VM, keeps state, and does not apply to Wasm or release builds.

open as a page

In Flutter 3.47, what is the Widget Previewer, how do you mark a widget with @Preview, and what can a preview not use?

level: middleimportance: nice to knowfreq 20%

basics

~20 s

The Widget Previewer renders single widgets outside the app, in the IDE or a browser. Annotate a public top-level function, static method or no-argument constructor with @Preview; it runs on Flutter web, so native plugins, dart:io and dart:ffi calls fail.

open as a page