Skip to content

prefer_container

v0.4.0WarningFixConfigurableWidget Replacement

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.

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 Container
Transform(
transform: Matrix4.identity(),
child: Padding(
padding: EdgeInsets.all(16),
child: Align(alignment: Alignment.center, child: Text('Hello')),
),
);
// Padding > ColoredBox > SizedBox can be replaced with Container
Padding(
padding: EdgeInsets.all(8),
child: ColoredBox(
color: Colors.red,
child: SizedBox(width: 100, height: 50, child: Text('World')),
),
);
// Single Container combines all properties
Container(
transform: Matrix4.identity(),
padding: EdgeInsets.all(16),
alignment: Alignment.center,
child: Text('Hello'),
);
// Single Container with color and size
Container(
padding: EdgeInsets.all(8),
color: Colors.red,
width: 100,
height: 50,
child: Text('World'),
);
// Only 2 nested widgets (below threshold) is fine
Padding(
padding: EdgeInsets.all(8),
child: Align(alignment: Alignment.center, child: Text('OK')),
);

This rule is in no preset, so it is off unless you enable it by name:

many_lints.yaml
rules:
prefer_container: true

To turn it off again:

many_lints.yaml
rules:
prefer_container: false

To keep the rule on but skip certain paths, use per-rule exclude.

analysis_options.yaml
many_lints:
rules:
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.