Skip to content

prefer_immutable_state

v1.0.0WarningFixConfigurableState Management

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_patternState$ by default — and the check is then widened to every subclass and implementor.

This rule is in the opinionated preset.

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

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';
@immutable
class LoginEmailState {
const LoginEmailState({this.isSubmitting = false});
final bool isSubmitting;
}

To disable this rule:

many_lints.yaml
rules:
prefer_immutable_state: false

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

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