Why Performance Matters
Performance is a critical aspect of any mobile app. A slow, janky app leads to poor user experience, lower ratings, and reduced engagement. Flutter is designed to deliver high performance out of the box, but certain practices can degrade performance. This guide covers essential optimization techniques to keep your Flutter apps smooth and responsive.
- Use
const Widgets Whenever Possible
const Widgets Whenever PossibleThe const keyword tells Flutter that a widget is constant and does not change. This allows Flutter to reuse the same instance across rebuilds, avoiding unnecessary allocations and comparisons.
Marking widgets as const is especially important in large lists, complex layouts, and inside build methods that run frequently. Use const constructors for your own widgets when possible.
- Avoid Unnecessary Rebuilds with
const and RepaintBoundary
const and RepaintBoundaryFlutter rebuilds parts of the widget tree when state changes. To prevent over‑rebuilding:
- Use
constwidgets – as above.
- Use
- Split large widgets into smaller ones so only affected parts rebuild.
- Use
RepaintBoundaryto isolate expensive parts of the UI from repaints (e.g., animations).
- Use
- Avoid creating new closures or objects inside build methods that cause rebuilds (e.g., pass a reference to a method rather than creating a new
VoidCallbackeach time).
- Avoid creating new closures or objects inside build methods that cause rebuilds (e.g., pass a reference to a method rather than creating a new
- Use
ListView.builder for Large Lists
ListView.builder for Large ListsListView.builder lazily builds items only when they scroll into view, instead of building all at once. This drastically reduces memory and build time for long lists.
Similarly, use GridView.builder and PageView.builder for other scrollable widgets.
- Use
ValueKey to Preserve State
ValueKey to Preserve StateWhen you reorder or modify a list, using Key helps Flutter differentiate widgets and preserve their state. ValueKey with a unique identifier is a good practice.
- Optimize Images and Assets
- Use the correct image format – WebP is often smaller than PNG.
- Provide responsive images – use
MediaQueryto load appropriately sized images.
- Provide responsive images – use
- Cache images –
Image.networkcaches automatically; consider usingcached_network_imagefor advanced caching.
- Cache images –
- Avoid using
Image.assetwith large images in many places – useprecacheImageto load them ahead of time.
- Avoid using
- Use
FutureBuilder and StreamBuilder Efficiently
FutureBuilder and StreamBuilder EfficientlyThese builders rebuild on each snapshot change. To avoid unnecessary rebuilds, ensure the future or stream references are stable (e.g., store them in the state).
- Use
AnimatedBuilder with Listenable to Reduce Rebuilds
AnimatedBuilder with Listenable to Reduce RebuildsInstead of calling setState inside an animation that triggers a full rebuild, use AnimatedBuilder which only rebuilds the part that depends on the animation.
- Avoid Expensive Operations in
build
buildThe build method can be called many times. Avoid performing heavy computations, file I/O, or network calls inside it. Do them in initState or asynchronously.
- Use
Offstage to Keep Widgets in the Tree but Hidden
Offstage to Keep Widgets in the Tree but HiddenInstead of conditionally building widgets with if statements, which may recreate them, you can use Offstage to keep them in the tree but hidden. This is useful for maintaining state when toggling visibility.
- Profile Your App
Use the Flutter DevTools profiler to identify performance bottlenecks. Run your app in profile mode (flutter run --profile) and inspect the timeline. Look for:
- Long build times
- Excessive repaints
- Heavy layout passes
- Janky animations
- Use
const for Widgets in Lists
const for Widgets in ListsIf you have static items in a list, mark them as const. This saves memory and build time.
- Avoid Large
setState Scopes
setState ScopesOnly call setState on the part of the widget tree that actually needs to update. If you have a complex widget, consider splitting into smaller widgets so that changes are isolated.
Key Takeaways
- Use
constwidgets as much as possible.
- Use
- Use lazy builders (
ListView.builder) for long lists.
- Use lazy builders (
- Isolate rebuilds with
RepaintBoundary.
- Isolate rebuilds with
- Avoid creating new objects in
buildmethods.
- Avoid creating new objects in
- Profile your app to find real bottlenecks.
- Use keys to preserve widget state.
- Optimize images and assets.
- Keep
setStatescopes small.
- Keep