Flutter CRUD Tutorial (2025) — Complete Flutter CRUD Example with SQLite

If you’re learning Flutter and want to build real-world apps that store, update, and manage data locally, understanding CRUD operationsCreate, 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.

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.