Skip to content

Hot Reload vs Hot Restart

Understand the difference between hot reload and hot restart in Flutter development.


What is it?

Hot reload and hot restart are two development features in Flutter that help you see changes quickly. Hot reload updates your app instantly while preserving state, whereas hot restart resets the entire application state but loads changes faster than a full rebuild.


Why does it exist?

Hot reload and hot restart exist to:

  • Speed up development by avoiding full rebuilds
  • Preserve or reset state based on development needs
  • Provide immediate feedback during coding
  • Reduce development time significantly
  • Enable rapid experimentation and iteration
  • Maintain developer flow and productivity

Hot Reload

Hot reload injects updated source code files into the running Dart VM without restarting the app.

// Original code
class MyHomePage extends StatefulWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Text('Hello World'),
      ),
    );
  }
}

// After hot reload - update the text
class MyHomePage extends StatefulWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Text('Hello Flutter!'), // Changed text
      ),
    );
  }
}

// Save file (Ctrl+S / Cmd+S)
// or press 'r' in terminal
// App updates instantly - state preserved!

What's happening here? - Hot reload injects new code into running app - State of the app is preserved - UI updates within 1-2 seconds - Most changes are hot reloadable - Does not restart the app - Maintains navigation stack and variables


Hot Restart

Hot restart resets the app state and rebuilds the entire widget tree from scratch.

// Original code with counter state
int _counter = 0;

void _incrementCounter() {
  setState(() {
    _counter++;
  });
}

// After hot restart
// The counter resets to 0
// The app rebuilds from the beginning
// State is completely cleared

// Press 'R' in terminal (Shift+R)
// App restarts with state reset
// But faster than full app restart

What's happening here? - Hot restart destroys all state - Rebuilds widget tree from scratch - Navigation stack is cleared - Variables reset to initial values - Faster than full app restart - Useful when hot reload doesn't work


When to Use Hot Reload

Hot reload is ideal for UI changes that don't affect the app state.

Good for hot reload:

// 1. Changing text content
Text('Hello World')  Text('Hello Flutter')

// 2. Changing colors
Colors.blue  Colors.red

// 3. Changing layout
Column  Row

// 4. Adding simple widgets
Container()  Container(padding: EdgeInsets.all(8))

// 5. Changing styles
style: TextStyle(fontSize: 16)  style: TextStyle(fontSize: 20)

Also good for:

// 6. Adding new functions that don't affect state
void _helperFunction() { ... }

// 7. Modifying business logic
bool isValid  bool isActive

// 8. Updating asset references
Image.asset('assets/logo.png')  Image.asset('assets/new_logo.png')

// 9. Changing theme values
primaryColor: Colors.blue  primaryColor: Colors.green

What's happening here? - Hot reload preserves user session - Keeps navigation history intact - Maintains form inputs and selections - Stateful widgets keep their data - Great for rapid UI iteration


When to Use Hot Restart

Hot restart is needed when changes affect the app state or initialization.

Required for hot restart:

// 1. Changing initState() methods
@override
void initState() {
  super.initState();
  fetchData(); // Changes to initialization
}

// 2. Changing global variables
var apiUrl = 'https://api.example.com'; // Changed URL

// 3. Changing main() function
void main() {
  runApp(MyApp()); // Changed to run different app
}

// 4. Changing app-level providers
runApp(Provider(create: (_) => AuthService()) // New provider

// 5. Changing theme initialization
theme: ThemeData.dark()  theme: ThemeData.light()

// 6. Navigation structure changes
home: HomeScreen()  home: LoginScreen()

Also needed for:

// 7. Changing static variables
static const String appName = 'MyApp'; // Changed

// 8. Changing app configuration
SharedPreferences preferences; // New initialization

// 9. State model changes
class User { String name; }  class User { String name; int age; }

What's happening here? - Hot restart resets everything - Re-runs all initializations - Useful after major changes - Ensures clean state - Verifies app starts correctly


Comparison Table

Feature Hot Reload Hot Restart Full Restart
Speed Fastest (1-2s) Medium (3-5s) Slow (10-30s+)
Preserves State ✅ Yes ❌ No ❌ No
Preserves Navigation ✅ Yes ❌ No ❌ No
Rebuilds Widget Tree ✅ Yes ✅ Yes ✅ Yes
Re-runs main() ❌ No ✅ Yes ✅ Yes
Re-initializes State ❌ No ✅ Yes ✅ Yes
Key 'r' key 'R' key 'flutter run'
Use Case UI changes State changes Major changes

Keyboard Shortcuts

During development, use these shortcuts to control the app.

# In terminal window where 'flutter run' is running:

r   # Hot reload (preserves state)
R   # Hot restart (resets state)
q   # Quit the app
h   # Show help

# Visual Studio Code shortcuts:
Ctrl+S (Windows) / Cmd+S (Mac)    # Hot reload on save
Ctrl+Shift+F5 (Windows)            # Hot restart
F5 (Windows)                       # Start debugging

# Android Studio shortcuts:
Ctrl+S (Windows) / Cmd+S (Mac)    # Hot reload on save
Ctrl+Shift+R (Windows)             # Hot restart
Shift+F10 (Windows)                # Run app

What's happening here? - 'r' is for quick hot reload - 'R' for complete hot restart - 'q' to quit the app entirely - IDEs have their own shortcuts - Shortcuts work across all platforms


Managing State During Hot Reload

Hot reload preserves state, but you need to handle it properly.

// Stateful widget with preserved state
class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: () {
            setState(() {
              _count++; // State preserved during hot reload
            });
          },
          child: Text('Increment'),
        ),
      ],
    );
  }
}

// During hot reload:
// - _count value is preserved
// - Button state is preserved
// - UI updates with new changes
// - App stays at current screen

What's happening here? - State values are maintained - Variables keep their values - Button presses still work - No data loss during UI updates - Perfect for iterative development


Hot Reload Limitations

Not all changes can be hot reloaded.

// Changes that WON'T work with hot reload:

// 1. Changing main() function
void main() {
  runApp(MyApp()); // Won't update
}

// 2. Changing initState()
@override
void initState() {
  super.initState();
  // Changes here won't apply
}

// 3. Changing app-level initialization
runApp(MyApp()); // Won't reflect

// 4. Changing global variable initializations
String apiKey = 'old_key'; // Won't update

// 5. Changing static fields
static const String appName = 'MyApp'; // Won't change

// 6. Changing assets
Image.asset('assets/logo.png'); // New asset might not load

// 7. Changing app theme
theme: ThemeData.light(); // Won't apply

What's happening here? - Some changes require full restart - App initialization only runs once - Static variables are not updated - Asset changes may not be detected - Use hot restart for these changes


Best Practices

Use Hot Reload for UI

// Good: Use hot reload for UI changes
@override
Widget build(BuildContext context) {
  return Container(
    color: Colors.blue, // Change to Colors.red
    child: Text('Hello'), // Change to 'Hello World'
  );
}

Use Hot Restart for State Changes

// Good: Use hot restart for state changes
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(), // Change to LoginScreen()
    );
  }
}

Save Frequently

// Save files frequently for hot reload
// Enable auto-save in IDE
// Watch for reload messages in terminal
// Check for errors in console

Common Mistakes

Not Checking Hot Reload Status

Wrong:

// Don't assume hot reload worked
// Look for console messages
// "Reloaded X of Y libraries"
// "Performing hot reload..."

Correct:

# Look for these messages:
Performing hot reload... 
Reloaded 2 of 2 libraries in 1,234ms.


Using Hot Reload for Breaking Changes

Wrong:

// Trying to hot reload initialization changes
@override
void initState() { // Change initialization
  super.initState();
  fetchData(); // This won't run
}

Correct:

// Use hot restart for these changes
@override
void initState() {
  super.initState();
  fetchData(); // Works after hot restart
}


Summary

Hot reload is faster and preserves state, making it ideal for UI changes. Hot restart resets the app state and is needed for initialization changes. Understanding when to use each feature speeds up development significantly.


Next Steps


Did You Know?

  • Hot reload can update code in less than a second
  • The record for hot reload speed is 0.5 seconds
  • Hot reload works on physical devices too
  • State restoration can be customized
  • Some changes automatically trigger hot reload on save
  • You can disable hot reload if needed