Skip to content

Rebuilds & Performance

Rebuilds are cheap — until they aren’t

Section titled “Rebuilds are cheap — until they aren’t”

Rebuilding a widget subtree is usually fast: Flutter diffs the new widgets against the elements and updates only what changed. The problem is doing it more than necessary — rebuilding a big subtree when one small piece changed, every frame of an animation. The levers below all reduce wasted rebuild and repaint work.

A const widget is created at compile time and canonicalized. When a parent rebuilds, Flutter sees the same const instance and skips rebuilding that subtree entirely.

// This subtree is const — it is built once and skipped on every parent rebuild.
const Padding(
padding: EdgeInsets.all(16),
child: Text('Static label'),
)

Adding const wherever a widget’s inputs are all compile-time constant is the cheapest performance win in Flutter. Turn on the prefer_const_constructors lint and obey it.

setState rebuilds the whole State’s build output. If a giant screen calls setState for a small counter, the whole screen rebuilds.

// ❌ setState here rebuilds the entire screen for one number.
// ✅ Pull the changing part into its own small StatefulWidget,
// so only that widget rebuilds. Keep the rest as const siblings.

The pattern: push state down to the smallest widget that needs it, and keep the surrounding widgets const so they stay put.

Lever 3: stable subtrees and RepaintBoundary

Section titled “Lever 3: stable subtrees and RepaintBoundary”
flowchart TB
  screen["Big screen (const, stable)"] --> counter["Small changing widget
(its own State)"]
  screen --> rest["const siblings
not rebuilt, not repainted"]
  counter --> rb["wrap heavy/animated part
in RepaintBoundary"]
Isolating the part that changes keeps the rest stable

A RepaintBoundary gives a subtree its own paint layer, so repainting it does not force its neighbors to repaint. Wrap an animation or a frequently-updating widget in one to contain the damage.

Don’t guess. Flutter DevTools shows rebuild counts (which widgets rebuild and how often), a timeline of frame times (spot the frames over budget), and the widget inspector. The workflow is: reproduce the jank, open the timeline, find the expensive frame, and see which subtree is doing too much.

Why does a const widget help performance?
What is the effect of calling setState in a large State class?
What does a RepaintBoundary do?
How should you find a performance problem?