Introduction
Flutter's hot reload feature preserves the state of your app by reusing existing State objects. However, when you add new fields to a State class and hot reload, those new fields are not initialized because the existing State instance is reused rather than recreated. This leads to null reference errors, unexpected behavior, or silent bugs where new fields retain default values instead of being properly initialized.
Symptoms
- After hot reload, newly added fields are null or uninitialized
NoSuchMethodError: The getter 'x' was called on null- Hot reload succeeds but app behavior is incorrect
- Console warning:
`- Warning: A State object's initState was not called during hot reload.
- The State object was not recreated, so initState will not be called again.
`- Hot restart fixes the issue, but you want to avoid restarting
Common Causes
- Adding instance variables to a
Stateclass without initializing them - Adding new members that depend on widget properties that are set in
initState - Changing the constructor signature of a
StatefulWidgetwithout updating state initialization - Modifying
finalfields inStateafter initial creation
Step-by-Step Fix
- 1.Understand when hot reload preserves state:
- 2.- Hot reload reuses existing
Stateobjects - 3.- New fields added to
Statewill have their default values (null for objects) - 4.-
initState()is NOT called during hot reload - 5.- Only the
build()method is re-executed - 6.For nullable fields, add null checks after hot reload:
- 7.```dart
- 8.class _CounterState extends State<Counter> {
- 9.int? _newField; // Added during hot reload - will be null
@override Widget build(BuildContext context) { // Safe check for field added during hot reload final value = _newField ?? 0; return Text('Value: $value'); } } ```
- 1.Use late initialization with guards:
- 2.```dart
- 3.class _MyState extends State<MyWidget> {
- 4.late final DataProcessor _processor;
- 5.bool _isInitialized = false;
@override void initState() { super.initState(); _initialize(); }
void _initialize() { _processor = DataProcessor(widget.config); _isInitialized = true; }
@override Widget build(BuildContext context) { if (!_isInitialized) { _initialize(); // Handle field added during hot reload } return Text(_processor.process()); } } ```
- 1.When state is corrupted, perform a hot restart:
- 2.```bash
- 3.# In the running flutter run terminal:
- 4.# Press 'R' for hot restart (capital R), not 'r' for hot reload
- 5.
` - 6.Or from command line:
- 7.```bash
- 8.flutter run --hot
- 9.# Then press R in the terminal
- 10.
` - 11.Use a state management solution that survives hot reload:
- 12.```dart
- 13.// Riverpod example - providers survive hot reload better
- 14.@riverpod
- 15.class Counter extends _$Counter {
- 16.@override
- 17.int build() => 0;
void increment() => state++; } ```
Prevention
- Perform a hot restart (R) instead of hot reload (r) after adding new fields
- Use nullable types for fields that might be uninitialized during development
- Consider using state management (Riverpod, Provider) for complex state
- Use
flutter run --hotand learn the difference between 'r' and 'R' - Save state to disk or use
RestorationMixinfor state that needs to survive restarts