prefer_immutable_state
This rule flags a class whose name marks it as state and which is missing the @immutable annotation. Which names count is decided by name_pattern — State$ by default — and the check is then widened to every subclass and implementor.
This rule is in the opinionated preset.
Why use this rule
Section titled “Why use this rule”State that can be mutated in place changes without anything observing the change. A Riverpod notifier that assigns to a field of its own state, rather than replacing the state object, updates nothing: the reference is the same, so no listener rebuilds and no widget redraws.
@immutable moves that failure to analysis time. The analyzer reports a non-final field where it is declared, instead of leaving the bug to surface as a screen that will not refresh.
This rule is deliberately state-management-agnostic: it covers Riverpod, a hand-rolled store, and any plain ...State value object equally. For Bloc and Cubit, prefer_immutable_bloc_state recognises the state class through the Bloc<E, S> type argument instead, which is exact rather than a name match.
See also: @immutable
Flutter State classes are never reported
Section titled “Flutter State classes are never reported”Every Flutter State<T> subclass is named ...State, and every one of them is meant to hold mutable fields — controllers, setState values, subscriptions. Annotating one @immutable would be wrong, so they are excluded by type, not by name.
Which base classes count as a Flutter State follows the shared state_base_classes option, so a project with its own state-like base can point the exclusion at it.
class LoginEmailState { LoginEmailState({this.isSubmitting = false});
bool isSubmitting;}import 'package:meta/meta.dart';
@immutableclass LoginEmailState { const LoginEmailState({this.isSubmitting = false});
final bool isSubmitting;}Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: prefer_immutable_state: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”many_lints: rules: prefer_immutable_state: name_pattern: '(State|Status)$'rules: prefer_immutable_state: name_pattern: '(State|Status)$'| Option | Type | Default | Description |
|---|---|---|---|
name_pattern |
regex | State$ |
Pattern identifying state classes by name. A name matched in its entirety is not reported, so the bare affix itself is never flagged |
Related rules
Section titled “Related rules”avoid_state_constructors— Avoid constructors with logic in State classes.prefer_immutable_bloc_state— Ensure Bloc and Cubit state classes are annotated with @immutable.avoid_empty_setstate— Don’t call setState with an empty callback.avoid_inherited_widget_in_initstate— Don’t look up inherited widgets inside initState.