Skip to content

Expert · Animations and performance · topic 38 of 50 · 35 min

Performance

Explanation

Smooth apps draw each frame within about 16 ms (60 fps) or less on high-refresh screens. Use const constructors, split big widgets so less rebuilds, keep build methods light, use lazy lists, size images sensibly (cacheWidth), and use keys when list items move. Measure in profile mode (flutter run --profile) on a real device with DevTools before optimising.

The frame budget

Flutter draws the screen as frames. At 60 frames per second, each frame has about 16 milliseconds; on 90 or 120 Hz phones, even less. If building, laying out and painting a frame takes longer, the frame is dropped, and the user sees stutter (jank), especially while scrolling or animating. Budget Android phones, common in India, have slower CPUs, so test on one if you can.

Measure first, in profile mode

Debug mode is slow on purpose (it supports hot reload and many checks), so never judge performance in debug. Run flutter run --profile on a real device: it is almost as fast as release but keeps the profiling tools. Open Flutter DevTools: the Performance view shows frame timings (red bars are slow frames), and the widget rebuild tracker shows what rebuilds too often.

bash
flutter run --profile        # measure here, on a real phone
flutter run --release        # what users get
Profile mode is not available on emulators for meaningful results; use a device.

const widgets

A const widget is created once at compile time and reused. When the parent rebuilds, Flutter sees the identical const widget and skips rebuilding it. Mark widgets const wherever their arguments are constant: const Text('Hello'), const SizedBox(height: 8), const Icon(Icons.add). The analyser (with flutter_lints) suggests where const is possible.

Smaller rebuilds

setState rebuilds the whole State's build method. If a big screen has one ticking timer, extracting the timer into its own small StatefulWidget means only that small widget rebuilds every second. The same idea applies to Provider's Consumer/select and Riverpod's narrow watches: rebuild as little as possible.

dart
// Instead of setState in the whole page every second:
class CountdownText extends StatefulWidget {
  const CountdownText({super.key});
  @override
  State<CountdownText> createState() => _CountdownTextState();
}

class _CountdownTextState extends State<CountdownText> {
  int _seconds = 300;
  Timer? _timer;
  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(const Duration(seconds: 1), (_) => setState(() => _seconds--));
  }
  @override
  void dispose() { _timer?.cancel(); super.dispose(); }
  @override
  Widget build(BuildContext context) => Text('OTP expires in $_seconds s');
}
Only this Text rebuilds each second, not the whole login page.

Keys

Keys help Flutter match widgets to their state when items are added, removed or reordered in a list. Use ValueKey(item.id) for items with an id, ObjectKey for objects, and UniqueKey to force a fresh widget. GlobalKey gives access to a widget's state from elsewhere (like FormState) but is expensive; use it only when needed.

Lists and images

  • Use ListView.builder and GridView.builder for long lists (module 6).
  • Images: a 4000 x 3000 photo shown at 100 x 100 still decodes the full image into memory. Use Image(cacheWidth: ...) or request smaller images from the server.
  • Cache network images (cached_network_image) so scrolling back does not re-download.
  • Move heavy computation off the main isolate with Isolate.run or compute (module 3).

RepaintBoundary, briefly

RepaintBoundary isolates a part of the screen that repaints often, like an animation, so the rest does not repaint with it. Flutter already adds them in many places (for example around list items); add your own only when DevTools shows excessive repainting.

Think of it like this: Performance work is like running a busy kitchen to serve a plate every 16 seconds. Pre-cooked items (const widgets) need no work; small cooking stations (small widgets) mean only one cook gets busy for each order; and you check the timer on real orders (profile mode) instead of guessing.

Common mistakes

  • Judging speed in debug mode.
  • Optimising without measuring: wasted time on parts that were already fast.
  • Heavy work in build (sorting, parsing, formatting a whole list) on every rebuild.
  • Using GlobalKeys and big setState calls everywhere.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Performance · 1/6

60 fps = 16 ms

Each frame has about sixteen milliseconds at sixty frames per second. Missed frames cause jank.

Prefer a video by a teacher? Find free videos on “flutter performance tips const profile mode devtools jank rebuilds” on YouTube ↗

In real life: Smoothing a laggy product feed

A shopping app's home feed stuttered on budget phones. Profiling in profile mode showed full-size product photos being decoded for small thumbnails and the whole page rebuilding every second because of a countdown banner. The team requested 400-pixel images from the CDN, set cacheWidth, moved the countdown into its own widget and added const where the analyser suggested. Scrolling became smooth on a ₹9,000 phone.

dart
Image.network(
  product.thumbnailUrl,
  width: 120,
  height: 120,
  cacheWidth: 240,          // decode at about 2x display size, not full resolution
  fit: BoxFit.cover,
)
Smaller decoded images use far less memory.

Practice (0/3 done)

Task 1 · Question

Which mode should you use to measure performance?

Task 2 · Question

A page with a 1-second countdown rebuilds everything every second. Best fix?

Task 3 · Practice

Take a list-heavy screen from your app. Run it in profile mode on a real phone with DevTools open, record the frame chart while scrolling, then apply three fixes (const widgets, smaller rebuild scope, cacheWidth or builder lists) and record again. Note the difference in slow frames.

Quick quiz

Question 1

1.Why does const help performance?

Question 2

2.What does cacheWidth on an Image do?

Question 3

3.Which key suits list items that have database ids?

Question 4

4.Why is debug mode not good for judging speed?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Why does const help performance?

Answer: Const widgets are created once and can be skipped during rebuilds

Identical const widgets are reused.

What does cacheWidth on an Image do?

Answer: Decodes the image at a smaller size to save memory

Avoids decoding full resolution for thumbnails.

Which key suits list items that have database ids?

Answer: ValueKey(item.id)

Stable identity from data.

Why is debug mode not good for judging speed?

Answer: It adds checks and hot reload support that slow it down

Use profile mode.

Which object holds a StatefulWidget's State between rebuilds?Related

Answer: The element

Elements are long-lived.

From Interview questions: Flutter

What are Baseline Profiles for?Related

Answer: Improving start-up and early frame performance through ahead-of-time compilation of key paths

They ship hints to compile hot code early.

From Debugging and performance

What is a widget?Related

Answer: An immutable description of part of the UI

Flutter rebuilds the screen from widgets.

From Everything is a widget

Why should the hero image NOT use loading="lazy"?Related

Answer: It is usually the LCP element, and lazy loading makes the browser wait before fetching it

Lazy loading is for images far down the page. On the hero it delays the largest paint and hurts LCP.

From Performance and Core Web Vitals

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Animations and performance”. The module exam comes next.
  2. Module 9 exam: Animations and performance · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Responsive design and testing. 50 topics left in the course before the final exam.

← Previous: Hero, page transitions and Lottie or Rive