If you’re learning Flutter and want to build real-world apps that store, update, and manage data locally, understanding CRUD operations — Create, Read, Update, Delete — is essential.
In this Flutter CRUD tutorial, we’ll build a simple Note-Taking App using SQLite, Flutter’s most common local database.
By the end of this guide, you’ll know how to:
✅ Insert (Create) new records
👀 Display (Read) data from a database
✏️ Modify (Update) existing data
❌ Remove (Delete) data
This is a complete Flutter CRUD example for 2025 — perfect for beginners and intermediate developers.
⚙️ Prerequisites
Before we start coding, make sure you have:
Flutter SDK (version 3.24 or newer)
VS Code or Android Studio
Basic knowledge of Dart
Emulator or physical device
If you’re brand-new to Flutter, check out our Flutter Getting Started Guide.
🧩 Step 1: Create a New Flutter Project
flutter create flutter_crud_app
cd flutter_crud_app
This creates a new Flutter app. We’ll modify it into a CRUD app.
🗄️ Step 2: Add SQLite Dependency
We’ll use the sqflite package for database management.
Edit your pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
sqflite: ^2.3.0
path_provider: ^2.1.2
Then run:
flutter pub get
🧱 Step 3: Create the Database Helper
Create a file lib/db_helper.dart and paste the following:
import ‘package:sqflite/sqflite.dart’;
import ‘package:path/path.dart’;
class DBHelper {
static Database? _database;
static const String DB_NAME = 'notes.db';
static const String TABLE = 'notes';
static const int VERSION = 1;
static Future get database async {
if (_database != null) return _database!;
_database = await initDB();
return _database!;
}
static Future initDB() async {
final dbPath = await getDatabasesPath();
String path = join(dbPath, DB_NAME);
return await openDatabase(
path,
version: VERSION,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE $TABLE (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
content TEXT
)
''');
},
);
}
static Future insert(Map data) async {
final db = await database;
return await db.insert(TABLE, data);
}
static Future>> query() async {
final db = await database;
return await db.query(TABLE);
}
static Future update(Map data) async {
final db = await database;
return await db.update(TABLE, data, where: ‘id = ?’, whereArgs: [data[‘id’]]);
}
static Future delete(int id) async {
final db = await database;
return await db.delete(TABLE, where: ‘id = ?’, whereArgs: [id]);
}
}
This helper class handles all our CRUD operations in Flutter.
🧰 Step 4: Create a Note Model
Create lib/note_model.dart:
dart
Copy code
class Note {
int? id;
String title;
String content;
Note({
this.id,
required this.title,
required this.content,
});
factory Note.fromMap(Map json) => Note(
id: json[‘id’],
title: json[‘title’],
content: json[‘content’],
);
Map toMap() => {
‘id’: id,
‘title’: title,
‘content’: content,
};
}
📱 Step 5: Build the UI for CRUD Operations
Replace your main.dart with the following code:
dart
Copy code
import ‘package:flutter/material.dart’;
import ‘db_helper.dart’;
import ‘note_model.dart’;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter CRUD Tutorial’,
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.indigo),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State createState() => _HomePageState();
}
class _HomePageState extends State {
List notes = [];
final titleController = TextEditingController();
final contentController = TextEditingController();
@override
void initState() {
super.initState();
fetchNotes();
}
void fetchNotes() async {
final data = await DBHelper.query();
setState(() {
notes = data.map((e) => Note.fromMap(e)).toList();
});
}
void addNote() async {
await DBHelper.insert({
‘title’: titleController.text,
‘content’: contentController.text,
});
titleController.clear();
contentController.clear();
fetchNotes();
}
void updateNote(Note note) async {
await DBHelper.update({
‘id’: note.id,
‘title’: titleController.text,
‘content’: contentController.text,
});
fetchNotes();
}
void deleteNote(int id) async {
await DBHelper.delete(id);
fetchNotes();
}
void showForm([Note? note]) {
if (note != null) {
titleController.text = note.title;
contentController.text = note.content;
}
showModalBottomSheet(
context: context,
builder: (_) => Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(controller: titleController, decoration: const InputDecoration(labelText: ‘Title’)),
TextField(controller: contentController, decoration: const InputDecoration(labelText: ‘Content’)),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
note == null ? addNote() : updateNote(note);
Navigator.of(context).pop();
},
child: Text(note == null ? ‘Add Note’ : ‘Update Note’),
)
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text(‘Flutter CRUD Tutorial’)),
body: ListView.builder(
itemCount: notes.length,
itemBuilder: (context, index) {
final note = notes[index];
return Card(
child: ListTile(
title: Text(note.title),
subtitle: Text(note.content),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => deleteNote(note.id!),
),
onTap: () => showForm(note),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => showForm(),
child: const Icon(Icons.add),
),
);
}
}
🚀 Step 6: Run the Flutter CRUD App
bash
Copy code
flutter run
Your app is now live! You can create, read, update, and delete notes locally using SQLite.
💡 Pro Tips for 2025 Flutter Developers
Use Drift (formerly Moor) for a reactive ORM approach.
Use Firebase Firestore for cloud-based CRUD.
Implement state management (Provider / Riverpod / Bloc) for scalable apps.
Validate input fields and handle errors properly.
Frequently Asked Questions (FAQ)
What does CRUD mean in Flutter?
CRUD stands for Create, Read, Update, Delete — core database operations in most apps.
Which database is best for Flutter CRUD?
Use SQLite (via sqflite) for offline data, or Firebase for cloud sync.
Can I build CRUD without a database?
Yes, but it won’t persist data after closing the app (e.g., using lists or shared_preferences).
How do I use Firebase for CRUD?
Replace SQLite functions with Firestore methods (add, get, update, delete).
🏁 Conclusion
You’ve built a fully functional Flutter CRUD App using SQLite! 🎉
This Flutter CRUD tutorial showed every step — from setting up the project to handling database operations.