Build a Simple Todo App with Flutter and Provider: 2025 Beginner’s Guide

🧭 Overview

In this guide, we’ll build a clean and simple Todo list app using Flutter and the Provider package. This is a perfect way to learn state management, Flutter widgets, and best practices — all in one.


📱 What You’ll Build

A minimal but functional app that allows users to:

  • Add todos
  • See a list of tasks
  • Remove completed tasks

🤔 Why Use Provider?

Provider is a lightweight state management tool built by the Flutter team. It helps you:

  • Share app data across widgets
  • Update UI automatically when data changes
  • Keep logic out of your UI

⚙️ Project Setup

Create a new Flutter project:

flutter create todo_provider
cd todo_provider

Add provider to your pubspec.yaml:

dependencies:
flutter:
sdk: flutter
provider: ^6.1.0

Run:

flutter pub get

🧩 Defining the Todo Model

Let’s start by creating a simple model.

Create lib/models/todo.dart:

class Todo {
final String id;
final String title;
bool isDone;

Todo({required this.id, required this.title, this.isDone = false});
}

🧠 Creating the Provider Class

Create lib/providers/todo_provider.dart:

import 'package:flutter/material.dart';
import '../models/todo.dart';

class TodoProvider with ChangeNotifier {
List<Todo> _todos = [];

List<Todo> get todos => _todos;

void addTodo(String title) {
final todo = Todo(
id: DateTime.now().toString(),
title: title,
);
_todos.add(todo);
notifyListeners();
}

void toggleTodo(String id) {
final index = _todos.indexWhere((todo) => todo.id == id);
_todos[index].isDone = !_todos[index].isDone;
notifyListeners();
}

void deleteTodo(String id) {
_todos.removeWhere((todo) => todo.id == id);
notifyListeners();
}
}

🎨 Building the UI

Update main.dart to include the provider:

void main() {
runApp(
ChangeNotifierProvider(
create: (context) => TodoProvider(),
child: MyApp(),
),
);
}

Basic UI:

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Todo',
home: TodoScreen(),
);
}
}

Create lib/screens/todo_screen.dart:

class TodoScreen extends StatelessWidget {
final TextEditingController _controller = TextEditingController();

@override
Widget build(BuildContext context) {
final todoProvider = Provider.of<TodoProvider>(context);
return Scaffold(
appBar: AppBar(title: Text('My Todos')),
body: Column(
children: [
Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: TextField(controller: _controller),
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
if (_controller.text.isNotEmpty) {
todoProvider.addTodo(_controller.text);
_controller.clear();
}
},
),
],
),
),
Expanded(
child: ListView.builder(
itemCount: todoProvider.todos.length,
itemBuilder: (ctx, i) {
final todo = todoProvider.todos[i];
return ListTile(
title: Text(
todo.title,
style: TextStyle(
decoration: todo.isDone ? TextDecoration.lineThrough : null,
),
),
leading: Checkbox(
value: todo.isDone,
onChanged: (_) => todoProvider.toggleTodo(todo.id),
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => todoProvider.deleteTodo(todo.id),
),
);
},
),
),
],
),
);
}
}

✅ Complete Source Code

You can find the full working code on GitHub


🔗 Next Steps

From here, you can:

  • Add persistent storage using shared_preferences or hive
  • Improve UI with flutter_hooks or riverpod
  • Turn this into a multi-screen app

👉 Continue with:
How to Save Flutter Todo Data Using Shared Preferences


📬 Subscribe for More

Want full tutorials, real-world app examples, and Flutter news?
Join the FlutterTalk Newsletter →

What is Provider in Flutter?

Provider is a state management library that allows Flutter widgets to react to data changes efficiently.

Is this Todo app production-ready?

It’s a basic prototype. For production, add error handling, persistent storage, and testing.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.