Getting Started with Flutter: Install, Your First App and Project Structure
A step-by-step guide from installing the Flutter SDK to running your first app and understanding the project structure, with tips that save you time at the start.
Choosing a state management approach is one of the first questions every Flutter developer faces. This article explains setState, Provider, Riverpod and Bloc with code and tells you which to choose for which project.

"State" is the data your UI is built from and that changes over time: a shopping-cart counter, the signed-in user, a search result. The core question is: where does that data live, and how does the UI update when it changes?
Enough for the local state of one widget (such as whether a panel is open):
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => count++),
child: Text('$count'),
);
}
}Trouble starts when several screens need the same data. Lift state up as far as you can, but past a point it gets complicated without proper tooling.
A thin layer over InheritedWidget. You create a ChangeNotifier and place it above your widgets in the tree:
class CartModel extends ChangeNotifier {
final List<String> items = [];
void add(String item) {
items.add(item);
notifyListeners();
}
}
// near the root
ChangeNotifierProvider(create: (_) => CartModel(), child: const MyApp());
// in any widget below
final cart = context.watch<CartModel>();Easy to learn and works great for small to medium projects.
The evolution of Provider: independent of BuildContext, easier to test and safer at compile time:
final counterProvider = NotifierProvider<Counter, int>(Counter.new);
class Counter extends Notifier<int> {
@override
int build() => 0;
void increment() => state++;
}
// in a ConsumerWidget
final count = ref.watch(counterProvider);
ref.read(counterProvider.notifier).increment();It also ships tools for asynchronous data such as network requests.
An "event to state" pattern. Every action is an event and the output is a new state. It needs more code, but its structure and predictability pay off for large teams and complex apps.
setState and ValueNotifier.The best state management tool is the one your team knows well.
The FastFlutter VIP course takes you from zero to a published app, with direct support from the instructor.