Introduction
State management in Flutter is one of those topics that seems simple at first, but gets complicated fast. If you've ever struggled to figure out the best way to share and manage data between widgets or across your app, you're not alone. With Flutter's reactive UI model, choosing the right approach can make your app faster, more maintainable, and easier to test.
This guide will walk you through:
What state is
The types of state
The most popular state management solutions
When and why to use each one
Real-world code examples
What is State?
In Flutter, state refers to any data that affects the UI. For example:
A user's login status
The text inside a form field
The current tab in a BottomNavigationBar
If data changes and your UI needs to update, its state.
Types of State
Flutter state can be categorized into:
1. Local State
Exists only in a single widget
Short-lived
Example: Whether a Switch is on or off
Use setState()
2. App-Wide (Shared) State
Shared across multiple widgets/screens
Longer-lived
Example: Current user's profile or app theme
Use: A state management solution like Provider, Riverpod, or Bloc
Popular State Management Approaches
1. Best for Local UI State
Simple counter example:
class CounterScreen extends StatefulWidget {
@override
_CounterScreenState createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(child: Text('Count: \$_count')),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child: Icon(Icons.add),
),
);
}
}
Pros
Built-in and simple.
Cons
Doesn't scale for shared/global state
2. Provider - Flutter's Official Recommendation
Setup
# pubspec.yaml
dependencies:
flutter:sdk: flutter
provider: ^6.0.0
Create the Provider
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
Use in app
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
),
);
}
In widget
final count = context.watch<Counter>().count;
context.read<Counter>().increment();
Pros
Scales well
Good documentation
Cons
Can get verbose with large models
3. Riverpod - A Better Provider
Setup
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.5.1Define a Provider
final counterProvider = StateProvider<int>((ref) => 0);Wrap your app
void main() {
runApp(
);
ProviderScope(child: MyApp()),
}Use in widgets
class HomeScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Text('Count: \$count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Icon(Icons.add),
),
);
}
}Pros
Pure Dart (no BuildContext needed)
Great for testing
Cleaner syntax
Cons
Newer, so smaller ecosystem
4. Bloc - Best for Large-Scale Projects
Bloc (Business Logic Component) uses streams to separate logic and UI.
Setup
# pubspec.yaml
dependencies:
flutter_bloc: ^8.1.1
bloc: ^8.1.0Create Bloc
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
}Use BlocProvider and BlocBuilder:
void main() {
runApp(
BlocProvider(
create: (_) => CounterCubit(),
child: MyApp(),
),
);
}BlocBuilder<CounterCubit, int>(
builder: (context, count) => Text('Count: \$count'),
)Pros
Highly testable
Clean architecture
Cons
Boilerplate heavy
Learning curve
5. GetX - Quick and Minimal
Setup
# pubspec.yaml
dependencies:
get: ^4.6.5Controller
class CounterController extends GetxController {
var count = 0.obs;
void increment() => count++;
}Use in UI
final controller = Get.put(CounterController());
Obx(() => Text('Count: \${controller.count}'))Pros
Includes routing and DI
Fast and easy
Cons
Breaks Flutter conventions
Can lead to tight coupling
Summary Table
| Use case | Best option |
|---|---|
| Simple UI Updates | setState() |
| Shared App-wide state | Provider or Riverpod |
| Enterprise app structure | Bloc |
| Quick MVP or Prototype | GetX |

Join the conversation! Your thoughts help the community grow.