Module 6
Topic 5

Performance Optimization

Writing fast, smooth Flutter apps that deliver 60fps experiences on any device.

Flutter Performance Docs DevTools Guide
Why Performance Matters

Generally, Flutter applications are performant by default , but you only need to avoid common pitfalls to get excellent performance. These best practice recommendations will help you write the most performant Flutter app possible.

🎯 The 16ms Rule

To achieve 60 frames per second (fps), each frame must be built and rendered in 16ms or less . Since Flutter has separate threads for building and rendering, you have 16ms for building and 16ms for rendering. For 120fps devices, aim for under 8ms total.

Build Performance
How efficiently widgets are rebuilt
🎨
Rendering Performance
How efficiently pixels are drawn
🧠
Memory Performance
How efficiently memory is used
Control build() Cost

The build() method is called frequently — every time an ancestor widget rebuilds. Here's how to keep it efficient:

✅ Build Cost Tips

  • Localize setState() – Only rebuild what needs to change
  • Use const widgets – Enables Flutter to short-circuit rebuilds
  • Use StatelessWidget – Prefer widgets over helper functions
  • Split large widgets – Break into smaller, focused widgets
  • Use AnimatedBuilder child parameter – Pre-build subtrees that don't change
Minimize Expensive Operations

1. Avoid saveLayer()

saveLayer() allocates an offscreen buffer and can cause jank. Widgets that trigger it:

  • Opacity (when opacity is not 0 or 1)
  • ShaderMask
  • ColorFilter
  • Chip (when disabledColorAlpha != 0xff)
  • Text (with overflowShader)

2. Minimize Clipping

Clipping is costly but doesn't use saveLayer() (unless using Clip.antiAliasWithSaveLayer ). However, it's still expensive.

3. Use StringBuffer for String Building

Lazy Lists and Grids

Be lazy! When building large grids or lists, use the lazy builder methods with callbacks. This ensures that only the visible portion of the screen is built at startup time.

💡 Lazy Loading Benefits

  • Faster initial load – Only builds what's visible
  • Less memory usage – Widgets are created and destroyed as needed
  • Better performance – Fewer widgets to maintain
  • Scalable – Can handle thousands of items
Avoid Intrinsic Passes

An intrinsic pass is a second layout pass that happens when widgets need to know the intrinsic size of their children (e.g., to make all cells the same size). This doubles the layout cost.

✅ How to Avoid Intrinsic Passes

  • Set fixed sizes – Use SizedBox with fixed dimensions
  • Use constraints – Let parent widgets provide constraints
  • Use ConstrainedBox – Set min/max constraints
  • Use LayoutBuilder – Get parent constraints dynamically
Optimize Animations

Animations can be expensive. Here's how to keep them smooth:

💡 Animation Optimization Tips

  • Use AnimatedBuilder child – Pre-build static subtrees
  • Avoid Opacity in animations – Use FadeInImage or AnimatedOpacity
  • Avoid clipping in animations – Pre-clip images before animating
  • Use RepaintBoundary – Isolate expensive repaints
Step-by-Step Performance Audit

Follow these steps to profile and optimize your Flutter app:

1.
Run in Profile Mode – Use flutter run --profile for accurate performance metrics
2.
Open DevTools – Use the Performance tab to record frame timings
3.
Check for jank – Look for frames taking > 16ms (red markers)
4.
Enable widget rebuild tracking – See which widgets are rebuilding frequently
5.
Check for saveLayer() calls – Enable checkerboard rendering to see overlay usage
6.
Analyze layout passes – Enable timeline tracking to see intrinsic passes
7.
Fix and re-measure – Apply optimizations and test again
Common Pitfalls
  • Using Opacity in animations – Each frame triggers saveLayer()
  • Large build() methods – Rebuild too much when setState() is called
  • Non-lazy lists – Building all items at once for large lists
  • Intrinsic widgets in lists – Causes expensive second layout pass
  • Overriding operator== on widgets – Causes O(N²) behavior
  • Helper functions for widgets – Can't be optimized like const widgets
  • Not using const constructors – Misses short-circuit optimization

✅ Quick Wins

  • Add const to constructors where possible
  • Use ListView.builder instead of ListView(children: [])
  • Use AnimatedBuilder with child parameter for static subtrees
  • Replace Opacity with withOpacity() on colors
  • Replace ClipRRect with borderRadius in decorations
  • Use StringBuffer instead of + for string concatenation
Resources

📚 Learning Resources

🔗 Related Lessons

🎯 Key Takeaway

Performance optimization is about being intentional with how you build your Flutter app. Focus on controlling build cost — localize setState() , use const constructors, and prefer widgets over functions. Minimize expensive operations like saveLayer() , opacity, and clipping. Be lazy with lists and grids using builder methods. Use DevTools to profile and identify bottlenecks. Remember, Flutter apps are performant by default — avoid common pitfalls and you'll deliver smooth 60fps experiences.