prefer_container
Flags chains of 3 or more nested widgets that can all be replaced with a single Container widget. Container internally composes Align, Padding, DecoratedBox, ConstrainedBox, Transform, ColoredBox, SizedBox, and other layout widgets — so nesting them individually is redundant.
The collapsible set is exactly Padding, Align, Center, ColoredBox, DecoratedBox, ConstrainedBox, SizedBox, Transform, ClipRRect, ClipOval, ClipPath, and FractionallySizedBox. Widgets Container cannot express — notably Opacity, IntrinsicHeight, IntrinsicWidth, and LimitedBox — are excluded, and a chain containing one of them is split rather than collapsed across it.
Why use this rule
Section titled “Why use this rule”Deeply nested single-purpose widgets make the widget tree harder to read and debug. When three or more of these widgets are stacked, collapsing them into a single Container reduces nesting, improves readability, and still gives you access to all the same properties. The rule only triggers when there are no conflicting parameters (e.g., two Padding widgets would conflict).
See also: Container | DecoratedBox | SizedBox | Dart lint: avoid_unnecessary_containers
// Transform > Padding > Align can be replaced with ContainerTransform( transform: Matrix4.identity(), child: Padding( padding: EdgeInsets.all(16), child: Align(alignment: Alignment.center, child: Text('Hello')), ),);
// Padding > ColoredBox > SizedBox can be replaced with ContainerPadding( padding: EdgeInsets.all(8), child: ColoredBox( color: Colors.red, child: SizedBox(width: 100, height: 50, child: Text('World')), ),);// Single Container combines all propertiesContainer( transform: Matrix4.identity(), padding: EdgeInsets.all(16), alignment: Alignment.center, child: Text('Hello'),);
// Single Container with color and sizeContainer( padding: EdgeInsets.all(8), color: Colors.red, width: 100, height: 50, child: Text('World'),);
// Only 2 nested widgets (below threshold) is finePadding( padding: EdgeInsets.all(8), child: Align(alignment: Alignment.center, child: Text('OK')),);Turning this rule off
Section titled “Turning this rule off”This rule is in no preset, so it is off unless you enable it by name:
rules: prefer_container: trueTo turn it off again:
rules: prefer_container: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”many_lints: rules: prefer_container: min_sequence: 4rules: prefer_container: min_sequence: 4| Option | Type | Default | Description |
|---|---|---|---|
min_sequence |
int | 3 |
Minimum number of consecutive Container-compatible widgets in a nesting chain before the rule reports |
Raise it to only flag deeper nesting; lower it to 2 to catch every collapsible pair.
Related rules
Section titled “Related rules”prefer_align_over_container— Opposing convention. Use Align instead of Container when only alignment is set.prefer_constrained_box_over_container— Opposing convention. Use ConstrainedBox instead of Container when only constraints is set.prefer_padding_over_container— Opposing convention. Use Padding instead of Container when only padding or margin is set.prefer_transform_over_container— Opposing convention. Use Transform instead of Container when only transform is set.