← Flutter & Dart

Flutter Fundamentals

What are `Key`s used for in Flutter, and when do you need them?

Show answer — try answering out loud first

Keys help Flutter identify widgets when it rebuilds the tree, so it correctly matches each widget with its state. You usually don't need them, but they become necessary when you reorder, add, or remove items from a list of stateful widgets, so the state doesn't get mixed up between items.

When Flutter rebuilds, it compares the new tree with the previous one to decide what to reuse. By default it compares by widget type and position. That works almost always, but it breaks when you change the order of same-type widgets that have state: Flutter can assign the wrong state to the wrong widget.

A Key gives each widget a stable identity so Flutter tracks it correctly even when it changes position.

Common types:

  • ValueKey: identity based on a value (for example, an id).
  • ObjectKey: identity based on an object.
  • UniqueKey: always-unique identity (forces Flutter to treat it as new).
  • GlobalKey: global identity; lets you access the widget's state or position from outside. It's the most expensive one; use it with care.
import 'package:flutter/material.dart';

// In a reorderable list of stateful widgets, keys prevent
// the state from "sticking" to the wrong item.
class TaskList extends StatelessWidget {
  final List<String> tasks;
  const TaskList({super.key, required this.tasks});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        for (final task in tasks)
          ListTile(
            key: ValueKey(task), // stable identity per task
            title: Text(task),
          ),
      ],
    );
  }
}

Putting UniqueKey() on widgets inside a build "just in case." Since UniqueKey() generates a different key every time, you force Flutter to destroy and recreate the widget (and lose its state) on every rebuild. That kills performance and causes strange behavior. Keys are used intentionally, not by default.

"Keys help Flutter identify widgets when it rebuilds the tree, so it matches each widget with its correct state. Most of the time I don't need them, because Flutter compares by type and position. But when I have a list of stateful widgets and I reorder, add, or remove them, I use a ValueKey with something unique like an id so the state doesn't get mixed up between items. I reserve GlobalKey for cases where I need to access the state from outside, because it's more expensive."

Quick challenge

You have a list of two stateful Checkboxes and, when you reorder them, the "checked" state stays in the wrong position. How do you fix it?

See answer

By assigning a stable, unique Key to each item, based on its identity (not its position). For example, key: ValueKey(item.id). That way Flutter tracks each Checkbox by its identity even when it changes place, and the state (checked/unchecked) travels with the correct item.