Skip to content
AgileLogics
6 min read

Performance

Prerequisites: Isolates and concurrency, Stateful widgets and user input

The first rule of performance work: measure before you change anything. Flutter apps are fast by default; most slowdowns come from a few specific mistakes.

Measure with DevTools

Dart DevTools (opened from VS Code or Android Studio) shows:

  • The Performance view — frame times. Each frame must be built and drawn in about 16ms for 60 frames per second; slow frames appear red ("jank").
  • The CPU profiler — which functions use the most time.
  • The Memory view — allocations and leaks.
  • Rebuild tracking — which widgets rebuild, and how often.

Always profile in profile mode (flutter run --profile) on a real device. Debug mode is much slower and not representative.

Common Flutter wins

  1. Use const widgets. A const widget is created once and skipped during rebuilds.
  2. Rebuild less. Split large build methods into smaller widgets, and listen to state as low in the tree as possible, so a change rebuilds only the widgets that depend on it.
  3. Lazy lists. Use ListView.builder for long lists, never a Column with hundreds of children.
  4. Keep build cheap. No sorting, filtering, or parsing in build — compute in the model and cache the result.
  5. Move heavy work off the UI isolate with Isolate.run or compute.
  6. Size images correctly. Decoding a 4000-pixel photo to show it at 100 pixels wastes memory and time; use cacheWidth/cacheHeight.

Measuring Dart code

void main() {
  final stopwatch = Stopwatch()..start();
  final squares = List.generate(1000000, (i) => i * i);
  stopwatch.stop();
  print('Built ${squares.length} values in under a second: ${stopwatch.elapsed.inSeconds < 1}');
}
Built 1000000 values in under a second: true

For reliable micro-benchmarks, the benchmark_harness package handles warm-up and repetition — the first runs of any code under the JIT are slower.

Release builds

flutter build and dart compile exe produce AOT-compiled native code, which is much faster to start and run than debug builds. Release builds also tree-shake unused code and icons, reducing app size — check what takes up space with flutter build apk --analyze-size.

Common mistakes

  • Judging performance from a debug build.
  • Calling setState high in the tree for a small change, rebuilding a whole screen instead of one widget.