Introduction
State management is a core concept in Flutter development. As your app grows, passing state down widget trees via constructors becomes tedious. The Flutter Provider package offers a lightweight, efficient way to share and react to state changes. In this tutorial, you’ll learn how to integrate Flutter Provider (and its close variant provider package) for simple state management. By the end, you’ll have a working counter app that updates UI automatically when data changes.
Adding Provider to Your Project
Open pubspec.yaml.
Add the provider dependency:
dependencies:
flutter:
sdk: flutter
provider
Run flutter pub get to install.
Import the library in your Dart files:
import 'package:provider/provider.dart';
Creating a ChangeNotifier
Provider uses classes that extend ChangeNotifier to hold mutable state. Below is a simple counter model. Whenever the count updates, listeners are notified, and the UI rebuilds.
import 'package:flutter/foundation.dart';
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}_count is private.
count is a public getter.
increment() mutates state and calls notifyListeners().
Providing and Consuming State
Wrap your app (or part of it) with a ChangeNotifierProvider. This makes the counter available to any descendant widget.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const CounterPage(),
);
}
}create lazily instantiates CounterModel.
Descendant widgets use context.watch<CounterModel>(), context.read<CounterModel>(), or Consumer<CounterModel>().
Updating the UI
In your CounterPage, display the current count and a button to increment. Use context.watch to rebuild when the model changes, and context.read to call methods without triggering rebuilds.
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
final counter = context.watch<CounterModel>().count;
return Scaffold(
appBar: AppBar(title: const Text('Provider Counter')),
body: Center(child: Text('Count: $counter')),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterModel>().increment(),
child: const Icon(Icons.add),
),
);
}
}context.watch<CounterModel>().count subscribes to updates.
context.read<CounterModel>().increment() invokes state change without rebuilding this widget.
Advanced Tips
• Using Consumer wraps only part of the widget tree, limiting rebuild scope.
• For multiple providers, use MultiProvider.
• Consider Selector or ProxyProvider for derived or combined state.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
You’ve set up a minimal Flutter Provider example, created a ChangeNotifier model, and connected it to your UI. This approach scales well: you can add more providers, aggregate data, and keep widgets focused on presentation. Flutter Provider delivers a clear separation between state and UI, enabling predictable and maintainable code.
With this foundation in Flutter Provider, you’re ready to explore more advanced state management patterns and deliver robust, reactive applications. Happy coding!