What compiler it uses in profile mode , release mode and debug mode in 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:
bashflutter run # Debug mode (default) flutter run --debug
How it works:
textDart 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:
bashflutter run --profile
How it works:
textDart 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:
bashflutter build apk --release # Android flutter build ios --release # iOS flutter build web --release # Web
How it works:
textDart 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
| Feature | Debug (JIT) | Profile (AOT) | Release (AOT) |
|---|---|---|---|
| Compiler | JIT (runtime) | AOT (ahead-of-time) | AOT (ahead-of-time) |
| Performance | Slow | Fast | Fastest |
| Hot Reload | ✅ Yes | ❌ No | ❌ No |
| DevTools | ✅ Full | ✅ Performance only | ❌ No |
| Assertions | ✅ Enabled | ❌ Disabled | ❌ Disabled |
| Binary Size | Large | Medium | Smallest |
| Optimization | None | High | Maximum |
| Emulator | ✅ Yes | ❌ No | ✅ Yes |
| Use Case | Development | Performance testing | Production |
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):
dartvoid 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):
dartvoid 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
dartimport '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).
dartvoid 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
dartvoid 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: included (larger binary)text
UnusedClass - Release: removed (smaller binary)text
UnusedClass
When to Use Which Mode
Debug Mode (JIT)
✅ Daily development
- Fast iteration with hot reload
- Debugging with breakpoints
- Assertions catch bugs early
bashflutter run
Profile Mode (AOT)
✅ Performance testing
- Test app performance before release
- Profile CPU/GPU usage
- Identify performance bottlenecks
bashflutter run --profile --device-id <physical-device>
Release Mode (AOT)
✅ Production builds
- Deploy to app stores
- Maximum performance
- Smallest binary size
bashflutter build apk --release flutter build ios --release
Platform-Specific Compilation
Android
| Mode | Compiler | Output |
|---|---|---|
| Debug | JIT | .apk with Dart VM |
| Profile | AOT | .apk with native code |
| Release | AOT | .apk with native code (optimized) |
iOS
| Mode | Compiler | Output |
|---|---|---|
| Debug | JIT | .app with Dart VM (simulator only) |
| Profile | AOT | .app with native code (device only) |
| Release | AOT | .ipa with native code (optimized) |
Web
| Mode | Compiler | Output |
|---|---|---|
| Debug | dart2js (dev) | .js (unoptimized) |
| Profile | dart2js | .js (optimized) |
| Release | dart2js | .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
| Mode | Compiler | Speed | Use Case |
|---|---|---|---|
| Debug | JIT | Slow | Development (hot reload) |
| Profile | AOT | Fast | Performance testing |
| Release | AOT | Fastest | Production deployment |
Key Takeaway: Always test performance in profile or release mode — debug mode performance is NOT representative!
Learn more: Flutter Build Modes