How to Stop Excessive Rebuilds in Your Flutter App

Table of contents
- How Flutter Really Rebuilds Widgets
- Common Rebuild Triggers
- Real-World Bug: App Feels Laggy on Every Tap
- Problem:
- Solution:
- How to Detect Rebuilds
- 1. Use debugPrintRebuildDirtyWidgets = true;
- 2. Wrap widgets in RepaintBoundary
- 3. Use Flutter DevTools
- Case Study: Flutter App Lagging on List Scroll
- Problem:
- Fix:
- Best Practices to Prevent Excessive Rebuilds
- Quick Tips
- Summary: What You Learned
- Final Thought
- Related Reads

You press a button.
You change one value.
Suddenly your whole screen rebuilds even widgets that had nothing to do with the change.
You might be thinking:
“But I only called
setState()
once… what’s the problem?”
Flutter is fast but unnecessary widget rebuilds can ruin performance, cause visual flicker, battery drain, and even crash low-end devices.
In this post, we’re going deep into:
What actually causes rebuilds
Real-world examples of excessive rebuilds
Tools to detect them
And how to fix them the right way
If you want your Flutter app to feel smooth, battery-friendly, and production-grade this is for you.
How Flutter Really Rebuilds Widgets
Flutter’s UI is declarative.
That means you don’t manually change UI elements you describe what the UI should look like at any given state.
When state changes, Flutter rebuilds affected widgets.
But here’s the catch:
Flutter rebuilds from the top of the widget tree down unless you break it into smaller, optimized parts.
And sometimes, it rebuilds more than you expected.
Common Rebuild Triggers
Here are the most common ways widgets get rebuilt (sometimes unnecessarily):
setState()
— Rebuilds the entire widget that called itInheritedWidget
(e.g.Theme
,MediaQuery
) — Rebuilds all widgets using it when it changesProvider
,Riverpod
,Bloc
— Depends on how you consume the state — poor use = unnecessary rebuildsParent widget rebuilds — All child widgets rebuild unless marked
const
or separated
Real-World Bug: App Feels Laggy on Every Tap
Let’s say you built a shopping cart screen:
class CartScreen extends StatefulWidget {
@override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
int quantity = 1;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Cart'),
ElevatedButton(
onPressed: () => setState(() => quantity++),
child: Text('Add'),
),
ProductImage(), // This shouldn't change
Text('Quantity: $quantity'),
],
);
}
}
Problem:
When you press “Add”, setState
triggers a rebuild of the entire CartScreen
, including ProductImage()
which is expensive to rebuild.
Solution:
Extract ProductImage
into a StatelessWidget
, outside the rebuild scope:
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Cart'),
ElevatedButton(
onPressed: () => setState(() => quantity++),
child: Text('Add'),
),
const ProductImage(), // const prevents rebuild!
Text('Quantity: $quantity'),
],
);
}
How to Detect Rebuilds
Flutter gives you a few powerful ways to catch excessive rebuilding:
1. Use debugPrintRebuildDirtyWidgets = true;
Add this in main()
:
void main() {
debugPrintRebuildDirtyWidgets = true;
runApp(MyApp());
}
Now every widget rebuild will be printed in the debug console.
2. Wrap widgets in RepaintBoundary
RepaintBoundary(
child: SomeExpensiveWidget(),
)
This separates the render pipeline Flutter won’t repaint this widget unless its own state changes.
3. Use Flutter DevTools
Go to Flutter DevTools > Performance > Rebuild Stats
You’ll see exactly which widgets rebuilt and how often.
This is gold when debugging complex UI behavior.
Case Study: Flutter App Lagging on List Scroll
A developer built a chat app. Each message item had:
Profile picture
Name
Last message
Timestamp
Online status
Whenever any new message arrived all messages were rebuilding. Why?
Problem:
They used a ListView.builder
, but placed the entire message list inside a widget that updated when any message changed.
BlocBuilder<ChatCubit, ChatState>(
builder: (context, state) {
return ListView.builder(
itemCount: state.messages.length,
itemBuilder: (context, index) {
return ChatTile(message: state.messages[index]);
},
);
},
)
Every time the ChatCubit
emitted a new message, the entire ListView
rebuilt.
Fix:
Use ListView.separated
or optimize rebuilds by checking which items actually changed, or use indexed rebuild logic (like flutter_bloc
’s buildWhen
).
Best Practices to Prevent Excessive Rebuilds
Do
Extract widgets into small, reusable components
Use
const
constructors when possibleUse
Selector
orConsumer
wisely in ProviderUse
buildWhen
/select
to control rebuild triggersUse
RepaintBoundary
for images, charts, maps
Don’t
Put all UI inside one giant
build()
Forget to mark stateless widgets as
const
Wrap entire widget trees in
BlocBuilder
Allow every state change to rebuild the whole tree
Let heavy widgets redraw every frame
Quick Tips
Use
const
liberally especially for static widgetsMemorize data or cache widgets if they don’t change often
Use
ValueNotifier
andValueListenableBuilder
for simple UI state (faster than full state management for small tasks)Profile with DevTools every time you add new UI logic
Summary: What You Learned
Flutter rebuilds widgets declaratively, but you control the scope
Rebuilding too much = lag, Jank, bad UX
Use tools like
debugPrintRebuildDirtyWidgets
,RepaintBoundary
, and DevToolsOptimize using
const
, smaller widgets, and smart state consumption
Final Thought
Your Flutter app may “work,” but that doesn’t mean it’s efficient.
Understanding how and when widgets rebuild helps you write smoother, cleaner, production-ready code.
So next time you face a lag or Jank that doesn’t make sense check who’s rebuilding. It might just be that innocent widget you forgot to const
.
Related Reads
Subscribe to my newsletter
Read articles from Md. Al - Amin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Md. Al - Amin
Md. Al - Amin
Experienced Android Developer with a demonstrated history of working for the IT industry. Skilled in JAVA, Dart, Flutter, and Teamwork. Strong Application Development professional with a Bachelor's degree focused in Computer Science & Engineering from Daffodil International University-DIU.