State Management in Flutter: Provider vs Riverpod
How Provider and Riverpod solve shared app state differently, and which one makes sense for a new Flutter project today.
Flutter compiles one Dart codebase to genuinely native iOS, Android, web, and desktop apps — no WebView, no JavaScript bridge. Here's how to go from zero to a real working app.
flutter create my_app
cd my_app
flutter run
flutter run hot-reloads on save — most UI changes appear in the running app in under a second, without losing the app's current state, which is what makes Flutter development feel fast compared to a native rebuild-and-relaunch cycle.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('My App')),
body: Center(child: Text('Hello, Flutter!')),
),
);
}
}
In Flutter, the app bar, the button, the padding around it, even the app itself are all widgets — composed together in a tree. There's no separate "layout language" (no XML, no CSS) — layout is just more widgets, like Padding, Row, and Column.
class Counter extends StatefulWidget {
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
void _increment() {
setState(() => _count++); // tells Flutter to rebuild this widget
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _increment,
child: Text('Count: $_count'),
);
}
}
setState() is the Flutter equivalent of React's setState — it's the signal that triggers a rebuild. Anything that never changes belongs in a StatelessWidget; anything with mutable state needs a StatefulWidget.
Row(
children: [
Expanded(child: Text('Left, takes remaining space')),
Icon(Icons.arrow_forward),
],
)
Expanded is how you tell a child in a Row/Column to fill available space — without it, widgets size to their content and leftover space is simply unused.
final response = await http.get(Uri.parse('https://api.example.com/posts'));
if (response.statusCode == 200) {
final posts = jsonDecode(response.body);
}
Once these basics click — widgets, state, layout, and a network call — you've covered the core loop that most real Flutter screens are built from.
How Provider and Riverpod solve shared app state differently, and which one makes sense for a new Flutter project today.