Hot Reload & Hot Restart
What is Hot Reload?
Hot reload is one of Flutter’s most powerful features. It allows you to inject updated source code into a running Dart Virtual Machine (VM) without restarting the entire application. The result? You see your changes reflected on screen in less than a second, while preserving the current state of your app.
This means if you are on a specific screen, have filled out a form, or scrolled to a certain position, all of that state is preserved when you hot reload. Only the code changes are applied.
How Hot Reload Works Internally
Understanding the internal mechanism helps you know when and why hot reload works or fails:
- You make a code change and save the file (or press the hot reload button)
- The Dart VM identifies which source files have changed since the last compilation
- The modified Dart source code is compiled into kernel files (incremental compilation)
- The new kernel files are injected into the running Dart VM
- The VM updates affected classes with the new field and function definitions
- The Flutter framework triggers a rebuild of the widget tree starting from the root
- The framework calls
build()methods on affected widgets - The updated UI appears on screen
Hot Reload in Action
// Before: Blue background
Scaffold(
backgroundColor: Colors.blue,
body: Center(
child: Text('Hello World'),
),
)
// After saving: Change to green -- hot reload applies instantly
Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Text('Hello World'),
),
)
Hot Reload vs Hot Restart vs Full Restart
Flutter provides three levels of reloading, each with different trade-offs between speed and completeness:
Hot Reload (Fastest)
Injects code changes without losing app state. Takes less than 1 second. Ideal for UI tweaks, style changes, and minor logic updates.
Triggering Hot Reload
# From terminal (when app is running with flutter run)
# Press: r
# VS Code
# Press: Ctrl+S (auto-save triggers hot reload)
# Or: Click the hot reload button (lightning bolt icon)
# Android Studio / IntelliJ
# Press: Ctrl+S (or Cmd+S on macOS)
# Or: Click the hot reload button in the toolbar
Hot Restart (Medium Speed)
Restarts the app from scratch without a full recompilation. Takes 2-5 seconds. The app state is lost, but it is much faster than a full restart. Use this when hot reload does not pick up your changes.
Triggering Hot Restart
# From terminal
# Press: R (capital R)
# VS Code
# Press: Ctrl+Shift+F5
# Or: Click the hot restart button (circular arrow icon)
# Android Studio / IntelliJ
# Click the hot restart button in the toolbar
Full Restart (Slowest)
Completely stops and rebuilds the application from scratch. Takes 10-30+ seconds. Required when you change native code, add plugins, or modify platform-specific files.
Triggering Full Restart
# Stop the app and run again
# Terminal: Press q to quit, then run flutter run again
# VS Code: Stop debugging, then start again (F5)
# Android Studio: Stop and re-run the application
r). If the changes do not appear, try hot restart (press R). Only do a full restart if neither works, which usually means you changed something outside of Dart code (like adding a new dependency or modifying Android/iOS configuration files).When Hot Reload Works
Hot reload works reliably in these common scenarios:
1. Changing Widget Properties
Modifying Widget Styles
// Change colors, sizes, padding, margins
Container(
padding: const EdgeInsets.all(16), // Change from 8 to 16
color: Colors.red, // Change from blue to red
child: Text(
'Styled Text',
style: TextStyle(
fontSize: 24, // Change from 18 to 24
fontWeight: FontWeight.bold, // Add bold
),
),
)
2. Modifying Build Methods
Updating the Widget Tree
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Welcome'),
// Add new widgets -- hot reload picks this up
Text('This is a new line!'),
ElevatedButton(
onPressed: () {},
child: Text('New Button'),
),
],
);
}
3. Changing Function Bodies
Updating Logic
void _incrementCounter() {
setState(() {
// Change from _counter++ to _counter += 5
_counter += 5;
});
}
When Hot Reload Does NOT Work
Hot reload has limitations. In these cases, you need a hot restart or full restart:
1. Changes to Global Variables and Static Fields
Global/Static Changes Require Hot Restart
// Changing these requires hot restart (R), not hot reload (r)
int globalCounter = 0; // Changing initial value
const String appName = 'MyApp'; // Changing const values
class MyService {
static final instance = MyService._(); // Changing static fields
MyService._();
}
2. Changes to initState()
initState Changes Need Hot Restart
@override
void initState() {
super.initState();
// Changes here will NOT take effect with hot reload
// because initState() only runs once when the widget
// is first inserted into the tree
_counter = 100; // This change needs hot restart
}
3. Changes to Enum Types
Enum Changes Require Hot Restart
// Adding or removing enum values requires hot restart
enum Status {
active,
inactive,
pending, // Adding this requires hot restart
}
4. Changes to Generic Type Arguments
Generic Type Changes
// Changing type parameters requires hot restart
class MyList<T> {
// Changing from MyList<T> to MyList<T extends Comparable>
// requires hot restart
}
Stateful Hot Reload -- Preserving State
One of the most valuable aspects of hot reload is that it preserves the State of StatefulWidgets. This is incredibly useful during development.
State Preservation Example
class _CounterPageState extends State<CounterPage> {
int _count = 0;
String _message = 'Hello';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// If _count is 42 and you change the Text style below,
// hot reload will update the style BUT _count stays at 42
Text(
'Count: \$_count',
style: TextStyle(
fontSize: 32, // Change this...
color: Colors.purple, // ...or this
),
),
Text(_message),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
child: Icon(Icons.add),
),
);
}
}
In this example, if you have tapped the button 42 times and then change the fontSize from 32 to 48, hot reload will update the text size but _count will remain at 42. You do not need to tap 42 times again to get back to the same state.
Practical Examples -- Live UI Tweaking
Let’s walk through a practical workflow of using hot reload to iteratively design a card widget.
Step 1: Start with a Basic Card
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Text('My Card'),
),
)
Step 2: Hot Reload -- Add Elevation and Shape
Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: EdgeInsets.all(16),
child: Text('My Card'),
),
)
Step 3: Hot Reload -- Add Color and More Content
Card(
elevation: 8,
color: Colors.teal.shade50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Card Title',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text('This is the card description.'),
],
),
),
)
Each change takes less than a second to appear on screen. This rapid feedback loop allows you to experiment with different designs quickly without waiting for full rebuilds.
Hot Reload Keyboard Shortcuts Summary
Here is a quick reference of all the keyboard shortcuts for reloading:
Keyboard Shortcuts Reference
# Terminal (flutter run)
r -- Hot reload
R -- Hot restart
q -- Quit
d -- Detach (leave app running)
h -- Show help menu
v -- Open Flutter DevTools
w -- Dump widget tree
t -- Dump render tree
p -- Toggle debug paint
# VS Code
Ctrl+S / Cmd+S -- Save (triggers hot reload)
Ctrl+Shift+F5 -- Hot restart
F5 -- Start/continue debugging
Shift+F5 -- Stop debugging
# Android Studio / IntelliJ
Ctrl+S / Cmd+S -- Save (triggers hot reload)
Ctrl+F5 -- Hot restart
Shift+F10 -- Run
Ctrl+F2 -- Stop
Limitations and Gotchas
Be aware of these additional limitations:
- Native code changes: Modifying
AndroidManifest.xml,Info.plist, Gradle files, or Podfile requires a full restart - Adding new packages: After running
flutter pub addor modifyingpubspec.yaml, you need a full restart - Asset changes: Adding new images or fonts to the assets folder requires a full restart
- Main function changes: Changes to the
main()function orrunApp()need a hot restart - Compile errors: If your code has errors, hot reload will fail. Fix the errors and try again
- Web platform: Hot reload on web uses a different mechanism (hot restart) that does not preserve state
Best Practices for Efficient Development
Follow these practices to get the most out of hot reload:
- Keep widgets small: Smaller widgets mean smaller rebuild scopes, making hot reload even faster
- Use const constructors: Widgets marked as
constare not rebuilt during hot reload, improving performance - Save frequently: Configure your editor to auto-save, which triggers hot reload automatically
- Watch the console: The terminal shows hot reload status and any warnings or errors
- Know when to restart: If something looks wrong after hot reload, do a hot restart before spending time debugging
Summary
In this lesson you learned:
- Hot reload injects updated code into the running Dart VM in under a second
- The difference between hot reload (preserves state), hot restart (loses state but fast), and full restart (complete rebuild)
- Hot reload works for widget changes, build methods, and function body updates
- Hot reload does NOT work for global variables, initState changes, enums, and generic type changes
- State is preserved during hot reload, which is invaluable for iterative UI development
- Essential keyboard shortcuts:
rfor hot reload,Rfor hot restart - When to use each type of reload for maximum productivity
Practice Exercise
Create a simple Flutter app with a StatefulWidget that has a counter and a text field. Run the app and increment the counter to 10. Then, without stopping the app, use hot reload to: (1) change the text style, (2) change the background color, (3) add a new button. Verify the counter stays at 10 after each hot reload. Then try changing the initial value in initState() and observe that hot reload does NOT apply the change -- you need hot restart.