Optimising Flutter App Performance: 9 Techniques for a Smooth 60 FPS

A slow app drives users away. These 9 practical techniques, from const and ListView.builder to DevTools and Isolates, help your Flutter app stay smooth even on weak devices.

3 min read1 views
Optimising Flutter App Performance: 9 Techniques for a Smooth 60 FPS

Flutter is fast by nature, but bad code can waste that speed. The target is 60 frames per second (about 16 ms per frame). These nine techniques will help.

#1. Measure first, optimise second

Always measure in profile mode on a real (preferably weak) phone, not in debug or on an emulator:

flutter run --profile

Then open Flutter DevTools and look at the Performance view. Red frames mean trouble.

#2. Use const

A const widget is not rebuilt every time:

const Padding(
  padding: EdgeInsets.all(16),
  child: Text('Title'),
)

The simple rule: add const wherever you can (the prefer_const_constructors lint reminds you).

#3. Keep rebuilds small

When state at the top of the tree changes, the entire subtree rebuilds. Split big widgets into smaller ones and keep state near where it is needed. Prefer several widget classes over one 300-line build method.

#4. Build large lists lazily

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, i) => ItemTile(items[i]),
)

ListView(children: [...]) builds every item at once, while builder builds only the visible ones. If items have a fixed height, also provide itemExtent.

#5. Load images properly

Showing a huge image at a small size wastes a lot of memory:

Image.network(url, cacheWidth: 400)

Use a cache such as cached_network_image for network images.

#6. Avoid Opacity and ClipRRect on big trees

They create separate layers (saveLayer), which are expensive. Alternatives: FadeTransition, AnimatedOpacity, and for rounded corners a decoration with borderRadius instead of ClipRRect over heavy content.

#7. Move heavy work off the main isolate

Large JSON parsing, compression or image conversion must not freeze the UI:

final result = await Isolate.run(() => parseHugeJson(text));

#8. Use RepaintBoundary deliberately

Wrap a constantly animating part in a RepaintBoundary so the rest of the screen is not repainted every frame. Do not sprinkle them everywhere though; every boundary has its own cost.

#9. Remove shrinkWrap and nested ListViews where possible

shrinkWrap: true on a big list measures every item and is slow. Use a CustomScrollView with a SliverList instead.

#Pre-release checklist

  • Profile mode on a weak device with no red frames.
  • All lists are lazy.
  • Images load at an appropriate size.
  • Heavy work runs in an Isolate.

Remember: premature optimisation without measurement only complicates code. DevTools first, then decide.

Learn Flutter the professional, project-based way

The FastFlutter VIP course takes you from zero to a published app, with direct support from the instructor.

View the VIP course