Hiprup

Compare Flutter's compilation modes: Debug, Profile, Release.

Three build modes with very different behavior:

Debug (default for flutter run) — JIT-compiled, full asserts, Hot Reload ON, service protocol ON for DevTools / debugger. 10-20× slower than release. For local development.

Profile (--profile) — AOT-compiled (like release), most optimizations on, Hot Reload OFF, service protocol ON for DevTools (profiling only, no debugger). Cannot run on emulators/simulators — real device only. For measuring real performance.

Release (--release / flutter build) — AOT-compiled, all optimizations on (tree-shaking, minification, no asserts), Hot Reload OFF, service protocol OFF. What you ship to the App Store / Play Store.

Use kDebugMode / kProfileMode / kReleaseMode from package:flutter/foundation.dart to gate code per mode.

import 'package:flutter/foundation.dart';

if (kDebugMode) print('only logged in debug');
if (kReleaseMode) reportToAnalytics('cold-start');

The compile-time constants kDebugMode, kProfileMode, and kReleaseMode from package:flutter/foundation.dart let you gate code per build mode. Because they're compile-time constants, the Dart compiler tree-shakes branches that can't run — print() calls inside if (kDebugMode) are entirely stripped from release builds, with no runtime cost.

Use this pattern for verbose dev logging or for analytics calls that should only fire in production.

Three details that signal seniority: (1) profile mode requires a real device — emulators/simulators don't reflect real performance; (2) never benchmark in debug mode — it's 10-20x slower than release; (3) kDebugMode / kReleaseMode / kProfileMode from package:flutter/foundation.dart let you conditionally include logging or analytics. The classic mistake to avoid in your answer: 'release mode is just debug with optimizations' — no, release mode uses a completely different Dart compilation pipeline (AOT vs JIT).

Compare Flutter's compilation modes: Debug, Profile, Release. | Hiprup