One of the most important concepts in Flutter development is understanding the difference between Stateless and Stateful widgets.
If Flutter is about building apps using widgets as building blocks, then knowing whether your widget should be stateless or stateful determines how you design your UI and how your app behaves.
In this article, we’ll go deep into:
- The definition of Stateless Widgets
- The definition of Stateful Widgets
- The key differences between the two
- Use cases for each
- How Flutter handles widget rebuilding
- Best practices for choosing the right widget type
- Common mistakes beginners make
- Real-world examples to help you decide
By the end, you’ll have a solid understanding of when to use Stateless vs Stateful widgets, which is one of the first major decisions you make in every Flutter app.
What is a Stateless Widget?
A Stateless Widget is a widget that does not change once built.
- It is immutable: meaning its properties are fixed during its lifetime.
- Whatever data you pass to it while creating remains the same.
- If something about the UI needs to change, Flutter will replace the entire widget with a new instance rather than modifying the existing one.
Example of a Stateless Widget
class MyTextWidget extends StatelessWidget {
final String message;
MyTextWidget({required this.message});
@override
Widget build(BuildContext context) {
return Text(message);
}
}
Here:
- The
messagepassed intoMyTextWidgetcannot change later. - If you want to show a new message, Flutter creates a new instance of the widget.
Characteristics of Stateless Widgets
- Immutable → Cannot change data after creation.
- Simple lifecycle → Only the
build()method is called. - Performance friendly → Since they don’t change, Flutter can optimize them.
- Examples in Flutter:
TextIconRaisedButton(deprecated, nowElevatedButton)Image
What is a Stateful Widget?
A Stateful Widget is a widget that can change during its lifetime because it holds a mutable state.
- It has two classes:
- The widget itself (
StatefulWidget) → immutable. - The
Stateclass → mutable, stores data that can change.
- The widget itself (
- Whenever the state changes, you call
setState(), which rebuilds the widget’s UI with updated data.
Example of a Stateful Widget
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int counter = 0;
void _incrementCounter() {
setState(() {
counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Counter: $counter"),
ElevatedButton(
onPressed: _incrementCounter,
child: Text("Increase"),
),
],
);
}
}
Here:
- The
countervariable changes when the button is pressed. - Calling
setState()tells Flutter to rebuild the UI with the new value.
Characteristics of Stateful Widgets
- Mutable → State can change dynamically.
- Complex lifecycle → Includes
initState(),build(),dispose(), etc. - Rebuilds frequently → Whenever state changes, Flutter calls
build(). - Examples in Flutter:
CheckboxTextFieldSliderForm
Stateless vs Stateful Widgets: The Core Difference
At the heart, the difference is immutability vs mutability.
| Feature | Stateless Widget | Stateful Widget |
|---|---|---|
| Mutability | Immutable | Mutable (can change) |
| Lifecycle | Simple (only build) | Complex (initState, build, dispose) |
| Data Handling | Data fixed at creation | Data can change dynamically |
| UI Updates | Requires new widget instance | Can update via setState |
| Example Widgets | Text, Icon, Image | Checkbox, Form, Counter |
When to Use Stateless Widgets
Use a Stateless Widget when:
- The UI does not depend on user input.
- The widget’s properties are fixed for its lifetime.
- The widget simply displays static information.
Examples:
- Displaying a logo image.
- Showing static text like a header.
- Icons in navigation bars.
- A styled container with background color.
When to Use Stateful Widgets
Use a Stateful Widget when:
- The UI needs to change dynamically.
- You need to respond to user interactions.
- The widget depends on real-time updates.
Examples:
- A counter app where numbers increase.
- A login form with input fields.
- A progress bar showing download status.
- A theme switcher (light/dark mode).
The Lifecycle Difference
Stateless widgets are straightforward:
- Create → Build → Done.
Stateful widgets have a more detailed lifecycle:
- createState() → Creates the state object.
- initState() → Called once when the widget is first created.
- build() → Describes the UI. Called multiple times.
- setState() → Triggers UI updates when state changes.
- dispose() → Called before the widget is destroyed (cleanup).
This makes Stateful widgets more powerful but also more resource-intensive.
Performance Considerations
- Stateless Widgets are lightweight, fast, and ideal for UI that doesn’t change.
- Stateful Widgets consume more memory and CPU because they manage state.
Best practice:
👉 Use Stateless Widgets whenever possible.
👉 Use Stateful Widgets only when you need state.
Common Mistakes Beginners Make
- Using Stateful when Stateless is enough
- Example: Creating a Stateful widget just to show static text.
- Overusing setState
- Calling setState too often can cause unnecessary rebuilds.
- Putting too much logic in a Stateful widget
- Instead, separate business logic using state management solutions (Provider, Riverpod, BLoC, etc.).
- Forgetting to dispose resources
- Example: Not closing a stream or controller in
dispose().
- Example: Not closing a stream or controller in
Real-World Examples
Example 1: Weather App
- The weather icon → Stateless (doesn’t change by itself).
- The temperature text → Stateful (updates when API data changes).
Example 2: Music Player
- The song title → Stateless.
- The progress bar → Stateful.
- The play/pause button → Stateful.
Example 3: E-Commerce App
- The product image and description → Stateless.
- The cart item count → Stateful.
- The wishlist button → Stateful.
How Flutter Rebuilds Widgets
- Stateless widgets are rebuilt from scratch whenever parent changes.
- Stateful widgets reuse their state object while updating only the necessary parts.
This efficiency makes Flutter smooth even with frequent UI updates.
Thinking in Terms of Stateless vs Stateful
When designing UIs, always ask:
- Does this part of UI depend on data that changes?
- If yes → Use StatefulWidget.
- If no → Use StatelessWidget.
This simple mental model will guide you to the right decision most of the time.
Best Practices
- Start with Stateless
- Convert to Stateful only if required.
- Keep State Local
- Only keep state in widgets that need it.
- Don’t lift state unnecessarily.
- Extract Widgets
- Break large Stateful widgets into smaller Stateless ones for better performance.
- Use State Management
- For large apps, use Provider, Riverpod, BLoC, Redux, etc.
Leave a Reply