Don’t use keys in widget constructors in apps
By default, Flutter wants you to have key
in every widget’s constructor:
Why using keys
There is a number of valid uses for keys:
- To keep widgets consistent when their order changes, as explained in a great video by the Flutter team.
- To deliberately reset a
StatefulWidget
’s state by creating its widget with another key. - To find a widget’s
RenderObject
to get its size. - To trace a widget’s state using
LabeledGlobalKey
. - To find a widget by a key in a test.
And maybe some more (post in the comments?)
Why not use keys in apps
The fact is, most of your widgets never use any of that. Take a look at the default Flutter Counter App:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp()); // Not using the key!
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// ...
But for some reason IDEs add keys for you, and Flutter complains if you remove a key.
The drawbacks of using keys in all widgets:
- It adds an extra line of code per widget.
- It dilutes the cases when you really need a key, so they are harder to notice in the code.
For this reason do not use keys in apps by default. If you ever need a key, you can add it later.
Disabling the lint
If you use the default Flutter’s linter, you can disable this lint by changing analysis_options.yaml
like this:
include: package:flutter_lints/flutter.yaml
linter:
rules:
use_key_in_widget_constructors: false
Alternatively, you can use my package total_lints
that enables a much stronger set of lints, but disables this one for you. For that, include app.yaml
in your analysis_options.yaml
:
include: package:total_lints/app.yaml
A word for packages
The above only applies to standalone apps. For packages you should have key
in every widget’s constructor. This is because with packages you do not know what their clients will need.
If you use total_lints
, include package.yaml
in your analysis_options.yaml
:
include: package:total_lints/package.yaml
It will require you to add keys properly.