State Management Tradeoffs
State management is an architecture decision, not a package contest.
Comparison
| Approach | Best for | Cost | Agent fit |
|---|---|---|---|
setState | Local visual state | Does not scale across screens | Good when kept local |
ValueNotifier | Small observable state | Manual composition | Good for tiny starters |
ChangeNotifier | Simple view models | Mutable state can sprawl | Good if APIs stay small |
| Provider | Inherited access and DI around notifiers | BuildContext coupling, package dependency | Good for simple apps with discipline |
| Riverpod | Explicit providers, async state, test overrides | New concepts, provider graph decisions | Strong when app state grows |
| Bloc/Cubit | Event/state discipline, auditability | Boilerplate and ceremony | Strong for complex flows, weak for tiny apps |
Recommendation
Use no default package in the stack pack. For actual app scaffolds:
- Start with local state and view models.
- If dependencies need clean overrides or async app state grows, use Riverpod.
- If workflows need explicit event logs and state transitions, use Bloc/Cubit.
- If the app is very small,
ChangeNotifier/Provider can be enough.
Red Flags
- One global app store for unrelated state.
- State package added before a second screen exists.
- View model methods that directly call platform channels.
- Persistent data stored only in memory state.
- Tests that pump a whole app to test simple state transitions.
Gotcha: State management packages do not fix unclear ownership. Decide who owns the data first: widget, screen, feature, repository, local database, or server.