Question #149MediumFlutter Basics

What compiler it uses in profile mode , release mode and debug mode in flutter?

#flutter

Answer

Overview

Flutter uses different compilers for each build mode to optimize for different goals: fast iteration (debug), realistic performance testing (profile), and maximum performance (release).


Debug Mode

Compiler: JIT (Just-In-Time)

Purpose: Fast development with hot reload.

Characteristics:

  • Code is compiled at runtime (not ahead of time)
  • Enables hot reload (inject code changes instantly)
  • Includes debugging symbols and assertions
  • Slower performance (not optimized)
  • Larger app size

Command:

bash
flutter run        # Debug mode (default)
flutter run --debug

How it works:

text
Dart Source Code
   JIT Compiler (runtime)
   Machine Code (on-demand)

Features:

  • ✅ Hot reload
  • ✅ Hot restart
  • ✅ DevTools support
  • ✅ Assertions enabled (
    text
    assert()
    )
  • ✅ Observatory (debugger)
  • ❌ Slow performance
  • ❌ Large binary

Profile Mode

Compiler: AOT (Ahead-Of-Time)

Purpose: Performance testing with some debugging.

Characteristics:

  • Code is compiled before running (ahead of time)
  • Near-release performance (optimized)
  • Includes profiling tools (performance overlay, tracing)
  • No hot reload (requires full rebuild)
  • Cannot run on emulators (physical devices only)

Command:

bash
flutter run --profile

How it works:

text
Dart Source Code
  AOT Compiler (compile-time)
  Native Machine Code (ARM, x86)
  Installed App

Features:

  • ✅ Near-release performance
  • ✅ Performance profiling tools
  • ✅ DevTools performance view
  • ❌ No hot reload
  • ❌ Physical device only (no emulator)

Release Mode

Compiler: AOT (Ahead-Of-Time)

Purpose: Production builds with maximum performance.

Characteristics:

  • Fully compiled to native machine code
  • Maximum optimization (tree shaking, minification)
  • No debugging tools (DevTools, assertions disabled)
  • Smallest binary size
  • Best performance

Command:

bash
flutter build apk --release       # Android
flutter build ios --release       # iOS
flutter build web --release       # Web

How it works:

text
Dart Source Code
  AOT Compiler (full optimization)
  Native Machine Code (ARM, x86)
  Optimized Binary (.apk, .ipa, .js)

Features:

  • ✅ Maximum performance
  • ✅ Smallest binary size
  • ✅ No debugging overhead
  • ✅ Tree shaking (unused code removed)
  • ❌ No debugging tools
  • ❌ No assertions
  • ❌ No hot reload

Comparison Table

FeatureDebug (JIT)Profile (AOT)Release (AOT)
CompilerJIT (runtime)AOT (ahead-of-time)AOT (ahead-of-time)
PerformanceSlowFastFastest
Hot Reload✅ Yes❌ No❌ No
DevTools✅ Full✅ Performance only❌ No
Assertions✅ Enabled❌ Disabled❌ Disabled
Binary SizeLargeMediumSmallest
OptimizationNoneHighMaximum
Emulator✅ Yes❌ No✅ Yes
Use CaseDevelopmentPerformance testingProduction

JIT vs AOT

JIT (Just-In-Time)

Compiles code at runtime (as it's executed).

Pros:

  • ✅ Fast iteration (hot reload)
  • ✅ No build time
  • ✅ Debugging support

Cons:

  • ❌ Slower execution
  • ❌ Larger binary

Example (Debug mode):

dart
void main() {
  print('Hello'); // Compiled when executed
}

AOT (Ahead-Of-Time)

Compiles code before running (at build time).

Pros:

  • ✅ Fast execution (native code)
  • ✅ Smaller binary (tree shaking)
  • ✅ Predictable performance

Cons:

  • ❌ Longer build time
  • ❌ No hot reload

Example (Release mode):

dart
void main() {
  print('Hello'); // Compiled to machine code during build
}

Build Commands

Debug

bash
# Run on device (JIT)
flutter run

# Build APK (includes debugging symbols)
flutter build apk --debug

Profile

bash
# Run on physical device (AOT, with profiling)
flutter run --profile

# Build APK
flutter build apk --profile

Release

bash
# Build optimized APK (AOT, fully optimized)
flutter build apk --release

# Build iOS app
flutter build ios --release

# Build web app
flutter build web --release

Checking Current Mode

dart
import 'package:flutter/foundation.dart';

void main() {
  if (kDebugMode) {
    print('Running in DEBUG mode (JIT)');
  } else if (kProfileMode) {
    print('Running in PROFILE mode (AOT)');
  } else if (kReleaseMode) {
    print('Running in RELEASE mode (AOT)');
  }
}

Assertions (Debug Only)

Assertions run only in debug mode (JIT).

dart
void setAge(int age) {
  assert(age >= 0, 'Age must be non-negative'); // ✅ Debug only

  if (kDebugMode) {
    print('Age set to $age');
  }
}

// Debug mode: throws if age < 0
// Release mode: assertion is removed (no-op)

Performance Differences

Example: Loop performance

dart
void main() {
  final stopwatch = Stopwatch()..start();

  for (int i = 0; i < 10000000; i++) {
    // Do nothing
  }

  stopwatch.stop();
  print('Time: ${stopwatch.elapsedMilliseconds}ms');
}

Results:

  • Debug (JIT): ~500ms
  • Profile (AOT): ~50ms
  • Release (AOT): ~50ms

Tree Shaking (Release Mode Only)

Removes unused code to reduce binary size.

dart
// lib/unused.dart
class UnusedClass {
  void unusedMethod() {
    print('This is never called');
  }
}

// main.dart
void main() {
  // UnusedClass is never imported or used
  print('Hello');
}

Result:

  • Debug:
    text
    UnusedClass
    included (larger binary)
  • Release:
    text
    UnusedClass
    removed (smaller binary)

When to Use Which Mode

Debug Mode (JIT)

Daily development

  • Fast iteration with hot reload
  • Debugging with breakpoints
  • Assertions catch bugs early
bash
flutter run

Profile Mode (AOT)

Performance testing

  • Test app performance before release
  • Profile CPU/GPU usage
  • Identify performance bottlenecks
bash
flutter run --profile --device-id <physical-device>

Release Mode (AOT)

Production builds

  • Deploy to app stores
  • Maximum performance
  • Smallest binary size
bash
flutter build apk --release
flutter build ios --release

Platform-Specific Compilation

Android

ModeCompilerOutput
DebugJIT.apk with Dart VM
ProfileAOT.apk with native code
ReleaseAOT.apk with native code (optimized)

iOS

ModeCompilerOutput
DebugJIT.app with Dart VM (simulator only)
ProfileAOT.app with native code (device only)
ReleaseAOT.ipa with native code (optimized)

Web

ModeCompilerOutput
Debugdart2js (dev).js (unoptimized)
Profiledart2js.js (optimized)
Releasedart2js.js (fully optimized, minified)

Best Practices

dart
// ✅ Use kDebugMode for debug-only code
if (kDebugMode) {
  print('Debug info');
}

// ✅ Use kReleaseMode for production-only code
if (kReleaseMode) {
  FirebaseCrashlytics.instance.crash(); // Production error tracking
}

// ✅ Test performance in profile mode before release
// flutter run --profile

// ❌ Don't test performance in debug mode
// Debug performance is NOT representative of release!

Summary

ModeCompilerSpeedUse Case
DebugJITSlowDevelopment (hot reload)
ProfileAOTFastPerformance testing
ReleaseAOTFastestProduction deployment

Key Takeaway: Always test performance in profile or release mode — debug mode performance is NOT representative!

Learn more: Flutter Build Modes