← BACK TO BLOGENTRY 06 / 08
MOBILE/7 MIN
Flutter State Management I Actually Use in Production
Provider, Riverpod, Bloc, GetX — I have tried all of them. Here is the small, boring stack I now reach for on every Flutter project, and the three rules I refuse to break.
KS
Kusal Salpura
Full-Stack Developer & Software Engineer
Flutter State Management I Actually Use
Flutter state management has a reputation for being a flame war. It is not. It is a solved problem, and the answer is Riverpod. The remaining question is how much Riverpod — and the answer is "less than you think".
The stack
- Riverpod 2 for everything that crosses widget boundaries.
useStatehooks (viaflutter_hooks) for purely local widget state — text controllers, animation tickers, toggle booleans.ChangeNotifierfor one thing only: form validation state. Riverpod can do this too, butChangeNotifieris genuinely simpler for the 12-field form case.
That is the entire stack. No Bloc. No GetX. No stacked services.
The three rules
- A provider is a side-effect boundary, not a state bag. If a provider just holds a value, use a
StateProviderand stop. If it does I/O, mutations, or coordinates multiple sources, then it earns aNotifierclass. - Never read a provider inside
buildthat you do not also subscribe to. Useref.watchfor things that should rebuild the widget. Useref.readinside callbacks only. Mixing these up is the source of 80% of Flutter bugs. - The widget tree is the source of truth. If you are passing data through five levels of constructors, you are reinventing
Providerbadly. Use Riverpod. But if you are pushing everything into Riverpod just to avoid prop drilling a single callback, you are over-engineering.
The architecture I land on
/lib
/features
/auth
auth_controller.dart -> NotifierProvider
auth_repository.dart -> interface
auth_repository_impl.dart -> talks to Firebase/Auth0/etc
/orders
...
/core
/router
/theme
/widgets -> shared presentational widgets
Feature folders. One repository interface per feature. One Riverpod Notifier per feature that the UI talks to. The UI never imports the repository directly.
What I deliberately do not use
- Bloc. Excellent for large teams, overkill for everything I have shipped. The boilerplate-to-value ratio is wrong for solo and small-team work.
- GetX. I have shipped a project with it. I will not do it again. The "everything in one package" pitch sounds great until you try to test or migrate.
- Redux (flutter_redux). I loved Redux on the web. In Flutter, Riverpod does the same job with less ceremony.
The takeaway
Pick Riverpod. Use it sparingly. Treat providers as side-effect boundaries, not state containers. The boring stack ships.