avoid_returning_widgets
This rule warns when a function, method, or getter returns a Widget. Building widgets inside helper methods is a common Flutter anti-pattern because the framework cannot optimize rebuilds for code that lives outside of a proper widget class.
Why use this rule
Section titled “Why use this rule”When you extract UI into a _buildHeader() method instead of a _Header widget class, Flutter treats the entire parent widget as a single unit. It cannot skip rebuilding the header when only something else changed. Proper widget classes give Flutter the information it needs to do fine-grained rebuilds, which directly improves performance in complex UIs.
See also: Flutter performance best practices
What is not reported
Section titled “What is not reported”Three shapes are exempt, because none of them collapses a subtree into the caller’s rebuild:
build()overrides — the standard way to build a widget.- A declaration passed as a callback rather than called, such as
Builder(builder: _row). The framework invokes it at its own point in the tree, so it behaves like a widget class rather than an inlined helper. A declaration that is called to build inline is still reported. - Functions annotated for a functional-widget generator —
@FunctionalWidget,@swidget,@hwidget,@hcwidget— which generate a real widget class, so the rewrite this rule asks for has already happened. Configurable throughignored_annotations.
A getter is never treated as a callback: => _body reads it rather than tearing
it off, so a bare reference to a Widget-returning getter is the inline build
this rule targets.
class MyScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Column(children: [_buildHeader(), _body]); }
// Helper method returning a widget Widget _buildHeader() => const Text('Header');
// Getter returning a widget Widget get _body => const Text('Body');}class MyScreen extends StatelessWidget { @override Widget build(BuildContext context) { return const Column(children: [_Header(), _Body()]); }}
class _Header extends StatelessWidget { const _Header();
@override Widget build(BuildContext context) => const Text('Header');}
class _Body extends StatelessWidget { const _Body();
@override Widget build(BuildContext context) => const Text('Body');}Turning this rule off
Section titled “Turning this rule off”This rule is in the recommended preset, so it is on with
preset: recommended (and with opinionated, which builds on it), or by name:
rules: avoid_returning_widgets: trueTo turn it off again:
rules: avoid_returning_widgets: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”many_lints: rules: avoid_returning_widgets: ignored_names: [buildLeading] additional_ignored_annotations: [widgetFactory] allow_nullable: truerules: avoid_returning_widgets: ignored_names: [buildLeading] additional_ignored_annotations: [widgetFactory] allow_nullable: true| Option | Type | Default | Description |
|---|---|---|---|
ignored_names |
list of strings | [] |
Method and function names never reported |
ignored_annotations |
list of strings | [FunctionalWidget, swidget, hwidget, hcwidget] |
Annotation names that exempt a member (written without @). Replaces the defaults; use additional_ignored_annotations to extend them |
additional_ignored_annotations |
list of strings | [] |
Annotation names to exempt in addition to the defaults |
allow_nullable |
bool | false |
Exempt nullable returns (Widget?), where null usually means “render nothing” |
Related rules
Section titled “Related rules”avoid_single_child_in_multi_child_widgets— Don’t use Column, Row, or other multi-child widgets with only one child.avoid_too_many_widgets_per_build— Keep one build method within a widget budget.avoid_unnecessary_consumer_widgets— Don’t extend ConsumerWidget if you never use WidgetRef.avoid_unnecessary_hook_widgets— Don’t extend HookWidget if you never call any hooks.