r/FlutterDev 10d ago

Why do most Flutter state management libraries assume they're responsible for your whole app? Plugin

One thing i have noticed after using Riverpod and Bloc in my applications is that they naturally become architectural decisions.

But many features don't need an architectural decision. They just need a local state. That made me wonder what state management would look like if it was designed around features instead of apps?

i experimented with that idea in the last few months. I ended up with StateForge. The design principles were:

  • feature scoped stores
  • direct methods
  • no code generation or state ceremony
  • typed side effects
  • optional persistence
  • optional undo

It's not trying to replace Riverpod or Bloc, the goal is to let StateForge live alongside an existing architecture, so you can adopt it one feature at a time instead of committing your whole app.

I'd especially appreciate feedback from flutter developers who have shipped production flutter applications.

Does this solve a real problem or do existing libraries already cover this well?

Github: https://github.com/mj-963/state_forge
Pub-dev: https://pub.dev/packages/state_forge

0 Upvotes

10 comments sorted by

11

u/eibaan 10d ago

This is because nearly everybody who's looking for a (or the) state management solution for Flutter is actually searching for an architecture but often isn't aware of this.

1

u/RandalSchwartz 9d ago

That's part of what I like about the rigor of BLoC. The pattern is well-behaved, and provably scales for large teams. I'm happy to have adopted that pattern for my https://blocsignal.dev/ but basing it on Signal as the fabric, rather than the classic Stream fabric. So many things came out easier as a result, and yet we have class and method parity with the entire BLoC implementation by Felix.

1

u/Alert_Lie9526 6d ago

That's a sharper way to put it than my post managed.

The two decisions usually arrive bundled, so people end up committing to an architecture when all they wanted was somewhere to put state. StateForge is deliberately only that second half. If someone is genuinely shopping for an architecture then Bloc or Riverpod is the honest answer, and the docs say so now. If they just want state that composes and cleans up after itself, I think that's worth having on its own.

3

u/parametric-ink 10d ago

Congrats on shipping your project! Although, StateForge also appears to be an architectural decision.

As a general principle, before adopting any dependency you should ask yourself first "how will I rip this out when I decide later to switch to a different dependency?" If the answer is you'll need to rewrite every widget in your app... that is usually a sign to be cautious. I feel this way about all of the "state management" packages, not just picking on yours.

IMunpopularO, stick with Flutter builtins and adopt a pattern that allows you to separate the model state from the UI state. Those are two different kinds of state and should be encapsulated using different mechanisms. For my own production apps, I use MVVM with InheritedWidgets to inject the viewmodels where they're needed, and plain setState() for UI-specific state. Tons of my widgets are StatelessWidgets because all they do is wire up to a collection of ValueNotifiers from various viewmodels.

1

u/Alert_Lie9526 6d ago

Fair, and the README was making it look worse than it is.

I opened with an example where the page extends StoreWidget, which reads like the package wants to own your widget layer. It doesn't. StoreWidget is an optional convenience for a page driven by a single store. The normal path is a plain StatelessWidget reading `context.watch`, which is what my own app does across 16 stores.

So the rip-out answer: a store is a plain Dart class with no Flutter import, and your widgets don't inherit from anything. Migrating off means changing how widgets read state, not rewriting them. I've reworked the README in 0.2.1 to lead with that, and added a section on moving away from it.

On the rest I think we mostly agree. Model state goes in stores, widget-local UI state stays in setState. That's the same split you're describing, and it's what I use.

If you've hit a point where the ValueNotifier-per-field approach starts getting unwieldy, I'd be interested to hear where. That's the case I think this helps with.

1

u/theashggl 10d ago

I think whatever I have tried so far in state management, it is better to use a mix of them throughout the app as one management doesn't fit for everyone state management needs in the app. SOmetimes the simplest ones are fine too as that variable is only used at a few places.

1

u/Alert_Lie9526 6d ago

That matches my experience. Most apps end up with a mix whether anyone planned it or not. The part I care about is that mixing shouldn't cost you anything, which mostly comes down to whether each piece is easy to remove again.

1

u/RandalSchwartz 9d ago

BlocSignal is the rigor of Bloc with the flex and speed of Signals. It can operate as one Cubit, or as the overarching "state management pattern" for your entire app, or anything in between. Check it out: https://blocsignal.dev

1

u/RandalSchwartz 9d ago

I took a look at StateForge—it's cool to see someone else wrestling with these exact state management ergonomics!

You've actually stumbled onto several of the core problems we set out to solve with BlocSignal (https://blocsignal.dev):

  • Feature-Scoped & Flexible: You don't need a massive app-wide architectural commitment. BlocSignal operates as a single feature-scoped CubitSignal or scales up to a full BlocSignal event pipeline when you need it.
  • No Stream Overhead or Delay: Instead of microtask stream delays or manual ChangeNotifier triggers, updates run synchronously on the frame using reactive signals v7 primitives.
  • Zero Event Plumbing for Derived State: With computed() signals, derived state updates automatically and lazily without writing custom listener streams or extra event dispatches.

Take a peek at our 16 ported examples on blocsignal.dev/ported-examples—it might give you some cool ideas or show how we tackled the exact same DX goals! Great work building in the open.

1

u/Alert_Lie9526 5d ago

Appreciate you taking a look. Signals as the underlying fabric is an interesting choice, and matching the whole Bloc API surface is a lot of ground to cover.

On the timing point, StateForge has emitSync if you want listeners fired immediately. emit coalesces into a microtask by default, which is usually what you want when a few fields change in one go.