use_sliver_prefix
Flags a widget whose build returns a sliver while the class name does not start with Sliver.
Slivers and box widgets are not interchangeable, and the type system does not separate them — both are just Widget. Drop a sliver-returning widget into a Column and you get a runtime error about RenderSliver not being a RenderBox, from a stack that points into the framework rather than at your file. The name is the only signal at the call site, which is why Flutter’s own framework uses it throughout. The quick fix renames the class.
This rule is in the pedantic preset.
See also: CustomScrollView
Enabling this rule
Section titled “Enabling this rule”rules: use_sliver_prefix: trueNothing at the call site says ProductList cannot go in a Column:
class ProductList extends StatelessWidget { const ProductList({super.key});
@override Widget build(BuildContext context) { return SliverList(delegate: SliverChildListDelegate([])); }}class SliverProductList extends StatelessWidget { const SliverProductList({super.key});
@override Widget build(BuildContext context) { return SliverList(delegate: SliverChildListDelegate([])); }}
// The name now makes the only valid parent obviousfinal scroll = CustomScrollView(slivers: const [SliverProductList()]);A StatefulWidget is judged by its State
Section titled “A StatefulWidget is judged by its State”The build lives on the State, but the diagnostic — and the rename — land on the widget class, since that is the name callers write:
// Don'tclass ProductHeader extends StatefulWidget { const ProductHeader({super.key});
@override State<ProductHeader> createState() => _ProductHeaderState();}
class _ProductHeaderState extends State<ProductHeader> { @override Widget build(BuildContext context) => const SliverAppBar();}
// Do — rename the widget; the private State follows for readabilityclass SliverProductHeader extends StatefulWidget { const SliverProductHeader({super.key});
@override State<SliverProductHeader> createState() => _SliverProductHeaderState();}
class _SliverProductHeaderState extends State<SliverProductHeader> { @override Widget build(BuildContext context) => const SliverAppBar();}A custom State base class
Section titled “A custom State base class”If your project’s state classes extend something of your own instead of Flutter’s State, name that base so the pairing still works:
many_lints: rules: use_sliver_prefix: state_base_classes: [AppState]rules: use_sliver_prefix: state_base_classes: [AppState]Known limitations
Section titled “Known limitations”Only a single-return build is examined. A build that branches — an if with two returns, or a body building a local first — is not reported even when every path returns a sliver:
// Not reported: two return statements@overrideWidget build(BuildContext context) { if (isEmpty) return const SliverToBoxAdapter(child: SizedBox()); return SliverList(delegate: SliverChildListDelegate([]));}Only Flutter’s own slivers count. The returned type must be declared in package:flutter and its name must start with Sliver, so a sliver from sliver_tools or one of your own does not trigger the rule.
Renaming the class is not automatic beyond the declaration — call sites are updated by your IDE’s rename refactoring, not by the quick fix.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
state_base_classes |
list of strings | [] |
Additional non-State base classes whose subclasses should be treated as state classes |
Turning this rule off
Section titled “Turning this rule off”rules: use_sliver_prefix: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”always_pass_global_key— Don’t create a GlobalKey inside build.avoid_conditional_hooks— Never call hooks inside conditionals, loops, or ternaries.avoid_deep_widget_nesting— Keep a widget tree within a nesting budget.avoid_flexible_outside_flex— Only use Flexible and Expanded as direct children of Row, Column, or Flex.