avoid_returning_widgets
Flags a function, method or getter whose return type is a Widget.
A _buildHeader() helper builds its subtree inside the caller’s build, so Flutter sees one element where you wrote two. It cannot skip the header when only the footer changed, cannot give it a const constructor, and cannot show it separately in the devtools tree. A _Header widget class costs the same lines and gets all three.
This rule is in the recommended preset, so it is on with preset: recommended and every preset above it.
See also: Flutter performance best practices
Methods and getters that return a widget are both reported:
class MyScreen extends StatelessWidget { const MyScreen({super.key});
@override Widget build(BuildContext context) { return Column(children: [_buildHeader(), _body]); }
Widget _buildHeader() => const Text('Header');
Widget get _body => const Text('Body');}class MyScreen extends StatelessWidget { const MyScreen({super.key});
@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');}A tear-off passed to a builder is exempt
Section titled “A tear-off passed to a builder is exempt”Handing the declaration to a builder: rather than calling it means the framework invokes it at its own point in the tree — that is a widget class in all but spelling, so it is not reported:
class Page extends StatelessWidget { const Page({super.key});
@override Widget build(BuildContext context) => Builder(builder: _row); // not reported
Widget _row(BuildContext context) => const Text('Row');}The exemption is for tear-offs only. Column(children: [_row(context)]) calls the same method inline and is still reported.
A getter is never treated as a tear-off: => _body reads it rather than tearing it off, so a bare reference to a Widget-returning getter is the inline build this rule targets.
Generated functional widgets are exempt
Section titled “Generated functional widgets are exempt”@swidget, @hwidget, @hcwidget and @FunctionalWidget generate a real widget class, so the rewrite this rule asks for has already happened:
@swidgetWidget productTile(BuildContext context, String name) => Text(name); // not reportedAdd your own generator’s annotation with additional_ignored_annotations:
rules: avoid_returning_widgets: additional_ignored_annotations: [widgetFactory]Nullable returns
Section titled “Nullable returns”Widget? usually means “render nothing”, which is not the helper-method pattern. It is reported by default; opt out with allow_nullable:
rules: avoid_returning_widgets: allow_nullable: true// Not reported under `allow_nullable: true`Widget? _badgeOrNothing() => count == 0 ? null : Text('$count');Known limitations
Section titled “Known limitations”A build() override is never reported — it is the standard way to build a widget.
The tear-off exemption matches on the name, not the resolved element. Two declarations in one file sharing a name means torn off one exempts both. That is deliberate: a false exemption is far cheaper than falsely reporting a legitimate builder callback.
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” |
Turning this rule off
Section titled “Turning this rule off”rules: avoid_returning_widgets: falseTo keep the rule on but skip certain paths, use per-rule exclude.
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.