skip to content

Debug, Profile & Release

Debug builds run JIT with asserts and service extensions, profile builds are AOT with tracing, release builds are AOT with neither. Interviewers ask why you never measure performance in debug.

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

explore

questions

5

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

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, 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

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

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