There still seems to be a lot of confusion about what’s “the best” state management library to use with Flutter.

Disappointingly, the right answer to these types of questions is always somewhere along the lines of “there’s no single best library - it all depends”.

“It depends?! Well, gee, thanks a lot for nothing! I guess I’ll try all the state management libraries in existence and figure out the best one myself. See you again around the time when my teeth fall out and I have dentures.”

Well, what does “the best state management library” mean to you?

If you’re looking for something that:

  1. scales when your app scales, and
  2. doesn’t make you want to create voodoo dolls out of the person who made the library and stab them in their ears with chopsticks

then fair enough.

You should know that most of the available state management libraries fit that criteria.

But you wouldn’t be on Reddit complaining that “there’s too many Flutter state management libraries!1!! I want fewer options!1!1” if this was your criteria.

In reality, you’re looking for “something that the Flutter team and the community as a whole 100% agree is the best library now and forever and that everybody will be forced to use until the heat death of the universe”.

Spoiler alert: there is no such thing. And, likely, there will never be such a thing.

“But why does it have to be popular?”, you ask.

“For two reasons”, I answer:

  1. The more popular it is, the more learning resources and examples it will have.
  2. It’s more likely that your colleagues are already somewhat familiar with it. Which means you can focus on building on whatever it is that you’re building.

And when I say “popular”, I don’t mean “the hot new thing that just appeared yesterday that everybody is talking about”.

You also want something that has been around for a while.

“So, what are some examples of popular libraries for state management?”

In no particular order, some of the most established options would be scoped_model, redux, mobx, bloc, and provider.

If you ask me, anything out of these usual suspects is a bit on the hit-or-miss territory.

“Okay, but that’s still five libraries, and I still don’t know which one to choose.”

That’s why we have the WIDJUP rule.

When In Doubt, Just Use Provider.

Provider is all you need for state management

If you’re overwhelmed by all the state management libraries and don’t know which one to choose, Just Use Provider™.

Provider has everything for your state management needs, both today and tomorrow.

Don’t get stuck in analysis paralysis; call 1-800-PROVIDER and get your very own Provider today!

“But Provider is not state management! It’s just a better InheritedWidget.”

You know what I mean.

Just like you know what your friend means when he tells you that he’s eating 8000 calories every day to prepare for a sumo wrestling competition. Yes, he means kilocalories, not calories. Everybody knows that.

But fine.

pedantic mode off

Turn on the switch. I hope that it makes you happy.

“Very funny.”

Thanks.

“Whatever. So, Provider is all I need? Isn’t that quite a bold statement?”

Not at all. Here’s a bold statement for you:

A bold statement.

“Sigh. What I meant is that can I use Provider in serious applications?”

Yes, just like you can use Provider in silly applications.

Such as in a fart soundboard app.

“Can you just stop with the dad jokes and write your articles like a normal person?”

*turns on professional mode*

Provider is mature enough

Provider is the most popular state management library on Pub.

It’s also probably the most liked library on Pub at 1.5k likes and counting. I say “probably”, because Pub doesn’t allow sorting by likes.

Aside from being popular, Provider has also existed for more than a year at this point. Having gone through several major version changes, the API should’ve stabilized enough by now.

Being popular, but not brand-spanking-new at the same time, is a good thing.

For what it’s worth, Provider is also recommended by Google and it has been recommended for over a year now.

It’s like scoped_model

Do you remember how back in the good old days, there were pretty much two viable state management libraries?

No? Well, Pepperidge Farm and a small group of early adopters remember.

Those two options were scoped_model and flutter_redux. Both packages have existed since August 2017.

“What does this have to do with Provider?”

I’ll show you.

Here’s one way to use scoped_model:

class Counter extends Model {
  int _counter = 0;
  int get counter => _counter;
  set counter(int value) {
    _counter = value;
    notifyListeners();
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // This assumes that there's ScopedModel<Counter>
    // widget somewhere in the widget tree and
    // it wraps "MyWidget".
    return ScopedModelDescendant<Counter>(
      builder: (_, __, model) => Text('${model.counter}'),
    );
  }
}

Here’s the same example, but with Provider:

class Counter extends ChangeNotifier {
  // The rest of it is the same.
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Assumes a ChangeNotifierProvider<Counter> above
    // in the widget tree.
    return Consumer<Counter>(
      // The rest of it is the same.
    );
  }
}

See the difference?

  1. with Provider, we extend ChangeNotifier instead of Model
  2. we pass the model around with ChangeNotifierProvider instead of ScopedModel
  3. we access the model with Consumer instead of ScopedModelDescendant

It’s the same thing, but with different names. There’s a guy from the ’80s with long hair who says it better than I ever could.

Okay, so scoped_model has existed for three years. And scoped_model and Provider are very similar. So what?

Well, it proves that the approach from scoped_model has stood the test of time. Three years and counting. It works.

It’s maybe even more than three years if you account for the fact that Fuchsia has been using the same approach internally before scoped_model extracted it to a package.

Provider is simple

While provider has more advanced classes such as ProxyProviders, you don’t have to use them.

All you need to get started is to know the following:

  1. use ChangeNotifiers to hold your state
  2. provide a ChangeNotifier to a subtree with ChangeNotifierProvider
  3. obtain a ChangeNotifier from ancestor widgets and rebuild automatically with Consumer.

There’s a good tutorial on the Flutter website on how to get started.

Once you become more comfortable with the concepts, you might want to take a look at Selector, which helps filter the data that triggers rebuilds to your widgets. But that’s really it.

Provider is scalable

Like many other state management libraries, Provider scales when your app scales.

But just like with scoped_model, it’s possible to shoot yourself in the foot by doing something weird.

Local state > global state

When I see people complaining about scoped_model or provider not being scalable, this is almost always what they are doing:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<MyNotifier1>(/* ... */),
        ChangeNotifierProvider<MyNotifier2>(/* ... */),
        ChangeNotifierProvider<MyNotifier3>(/* ... */),

        // * a few ChangeNotifierProviders later *
        ChangeNotifierProvider<MyNotifier99>(/* ... */),
      ],
      child: MaterialApp(/* ... */),
    ),
  );
}

In this case, instead of wrapping individual routes with their equivalent ChangeNotifiers, someone decided to make everything sit above the whole app.

This lifts local state into heights where it doesn’t have to go to.

There’s suddenly no boundaries on who accesses what. This, in turn, makes it impossible to dispose of unneeded ChangeNotifiers when users navigate away from their relevant routes.

Sharing a ChangeNotifier between many distinct routes also tends to result in very bloated ChangeNotifiers. This is not fun when your app starts having a lot of routes.

If you keep your state local, there’s no real reason why Provider wouldn’t scale with your app.

You’re probably already depending on provider

Given the popularity of provider, chances are that you already have it in your pubspec file. If not, you might be depending on a library that uses it internally.

And if you’re already depending on it, why not just go ahead and use the same thing to manage state too?

But what about clean architecture?

It’s a good idea to separate business logic from the UI framework.

But it’s also a good idea to be pragmatic about it.

Most apps don’t have to go all-in with clean architecture just because that’s how you get the most internet points from your enterprise Java friends.

If you’re a single developer hoping to build a successful app, you don’t want to get stuck wondering how to plumb Interactors together with Presenters, Services, Repositories, and then write the mappers that convert them in and out of domain models.

What you want to do instead is to build the MVP and ship it.

But if it’s a hobby app, and your sole purpose is to learn how clean architecture works, then it’s a very different story. In that case, the answer is “manage state with something that doesn’t have Flutter dependencies”.

But what about <insert new shiny state management library here>?

Do you remember the advice at the very beginning?

Pick a popular library and stick with it.

Think about this:

You could’ve been using scoped_model since 2017, ignoring all the other state management libraries in between (even Provider), and you would be fine today. Yeah, really.

A new state management library coming out today doesn’t suddenly make your existing code rotten.

Stop chasing shiny things

As an example, look at Invoice Ninja.

Out of scoped_model and flutter_redux, Invoice Ninja chose flutter_redux. And they stuck with it.

They released their first version back in the summer of 2018. Even back then, a large portion of the Flutter developer community didn’t really like Redux. But that didn’t matter.

Redux worked fine for Invoice Ninja, and that was the only thing that mattered. They still use Redux to this day.

Sure, Redux is boilerplatey, and it has its flaws, but it doesn’t matter. The virtue of using the newest and hippest community-approved libraries doesn’t necessarily make your business succeed.

Just build it already

You know what makes your business succeed?

Shipping useful apps does.

Invoice Ninja didn’t keep chasing the coolest state management library of the week. They didn’t complain about there being “too many state management libraries”. And they still don’t.

Invoice Ninja picked a state management library, stuck to it, and focused on their business instead of worrying if people think that Redux is cool enough.

Want to hear a secret?

You can do it too.

But instead of picking a library and starting to build apps with it, you sit on your hands and complain on Reddit that there are too many state management libraries.