Skip to content
Sign in

SAMPLE: Flutter State Management — setState vs Provider vs Riverpod

SAMPLE post. A practical comparison of three Flutter state management approaches with code and a decision table.

CodeOrbit Team (SAMPLE)Published 2 min read

State is any data that can change while your app runs. Flutter rebuilds widgets when state changes, so where you keep state decides how much of the tree rebuilds.

1. setState: local, simple

Use setState for state that belongs to a single widget, like a toggle or a text field.

Dart
class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: () => setState(() => _count++),
      child: Text('Tapped $_count times'),
    );
  }
}

2. Provider: shared, familiar

Provider wraps InheritedWidget so you can share a ChangeNotifier down the tree.

Dart
class CartModel extends ChangeNotifier {
  final List<String> _items = [];
  List<String> get items => List.unmodifiable(_items);

  void add(String item) {
    _items.add(item);
    notifyListeners();
  }
}

3. Riverpod: compile-safe, testable

Riverpod providers are global declarations that do not depend on BuildContext, which makes testing easier.

Dart
final counterProvider = StateProvider<int>((ref) => 0);

Which one should you pick?

Approach

Best for

Boilerplate

Testability

setState

Single-widget UI state

Very low

Basic

Provider

Small–medium apps

Low

Good

Riverpod

Medium–large apps

Medium

Excellent

  • Start with setState; lift state up only when two widgets need it.
  • Prefer immutable state objects; they make rebuilds predictable.

Tags:#Flutter#Dart

Frequently asked questions

Is setState bad practice?

No. It is the right tool for state that lives inside one widget.

Can I mix Provider and Riverpod?

Technically yes, but pick one per app to keep the codebase consistent.