What is the difference between StatelessWidget and StatefulWidget?
Short Answer
A StatelessWidget is immutable and rebuilds only when its parent rebuilds; a StatefulWidget holds mutable state via a separate State object and can rebuild itself whenever that state changes.
A StatelessWidget describes part of the UI that depends only on the configuration passed into it and the BuildContext. Once built, it never changes on its own — it's recreated wholesale whenever its parent rebuilds it with new data.
A StatefulWidget is split into two classes: the widget itself (immutable, just configuration) and a State object that Flutter keeps alive across rebuilds. Calling setState() inside the State object marks it dirty and schedules a rebuild of just that subtree, without needing the parent to rebuild.
Code Example
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
void _increment() => setState(() => _count++);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _increment,
child: Text('Count: $_count'),
);
}
}Common Mistakes
- ×Calling setState() after the widget has been disposed (always guard with `mounted` checks in async callbacks).
- ×Putting state in a StatelessWidget by mutating a field directly — it won't trigger a rebuild.
Interview Tips
- →Explain *why* the split exists: the State object survives widget rebuilds, which is how Flutter preserves things like scroll position and animation controllers.
Related Questions
Explain the widget lifecycle in Flutter.
A StatefulWidget's State goes through createState → initState → didChangeDependencies → build (repeated) → didUpdateWidget (on parent rebuild) → deactivate → dispose.
How do you avoid unnecessary widget rebuilds in Flutter?
Scope state narrowly (so only the widgets that depend on it rebuild), use `const` constructors wherever possible, and split large build methods into smaller widgets so a change in one part doesn't force the whole tree to re-render.