Flutter Sqflite (SQLite)
Powerful local database for Flutter applications
🗄️ What is Sqflite?
Sqflite is a Flutter plugin for SQLite database operations. It provides a powerful relational database solution for storing structured data locally, supporting complex queries, transactions, and relationships between tables for robust data management.
// Add to pubspec.yaml
dependencies:
sqflite: ^2.3.0
path: ^1.8.3
// Create database
final database = await openDatabase('my_database.db');
Key Features
SQL Queries
Full SQL support for data operations
await db.query('users');
Relationships
Create tables with foreign keys
FOREIGN KEY (userId)
REFERENCES users(id)
Transactions
Batch operations safely
await db.transaction((txn) {
// Multiple operations
});
Complex Queries
WHERE, JOIN, ORDER BY support
WHERE age > 18
ORDER BY name
🔹 Installation
Add required packages to your project:
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
sqflite: ^2.3.0
path: ^1.8.3
The
path
package helps locate the database file
🔹 Creating a Database
Set up your database with tables:
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await initDatabase();
return _database!;
}
Future<Database> initDatabase() async {
String path = join(await getDatabasesPath(), 'app_database.db');
return await openDatabase(
path,
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
age INTEGER
)
''');
},
);
}
}
Result:
✅ Database created with 'users' table
🔹 Insert Data
Add records to your database:
Future<int> insertUser(Map<String, dynamic> user) async {
final db = await database;
// Method 1: Using insert
int id = await db.insert(
'users',
user,
conflictAlgorithm: ConflictAlgorithm.replace,
);
return id;
}
// Usage
Map<String, dynamic> newUser = {
'name': 'Alice Smith',
'email': '[email protected]',
'age': 28,
};
int userId = await insertUser(newUser);
print('Inserted user with ID: $userId');
Output:
Inserted user with ID: 1
🔹 Query Data
Retrieve data from the database:
// Get all users
Future<List<Map<String, dynamic>>> getAllUsers() async {
final db = await database;
return await db.query('users');
}
// Get user by ID
Future<Map<String, dynamic>?> getUserById(int id) async {
final db = await database;
List<Map<String, dynamic>> results = await db.query(
'users',
where: 'id = ?',
whereArgs: [id],
);
return results.isNotEmpty ? results.first : null;
}
// Get users with condition
Future<List<Map<String, dynamic>>> getAdultUsers() async {
final db = await database;
return await db.query(
'users',
where: 'age >= ?',
whereArgs: [18],
orderBy: 'name ASC',
);
}
Result:
[{id: 1, name: Alice Smith, email: [email protected], age: 28}]
🔹 Update Data
Modify existing records:
Future<int> updateUser(int id, Map<String, dynamic> user) async {
final db = await database;
return await db.update(
'users',
user,
where: 'id = ?',
whereArgs: [id],
);
}
// Usage
await updateUser(1, {
'name': 'Alice Johnson',
'age': 29,
});
print('User updated successfully');
Output:
User updated successfully
🔹 Delete Data
Remove records from the database:
Future<int> deleteUser(int id) async {
final db = await database;
return await db.delete(
'users',
where: 'id = ?',
whereArgs: [id],
);
}
// Delete all users
Future<int> deleteAllUsers() async {
final db = await database;
return await db.delete('users');
}
🔹 Complete Example
A simple user management app:
class User {
final int? id;
final String name;
final String email;
final int age;
User({this.id, required this.name, required this.email, required this.age});
Map<String, dynamic> toMap() {
return {'id': id, 'name': name, 'email': email, 'age': age};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'],
name: map['name'],
email: map['email'],
age: map['age'],
);
}
}
// Usage in a widget
class UserListPage extends StatefulWidget {
@override
_UserListPageState createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
final dbHelper = DatabaseHelper();
List<User> users = [];
@override
void initState() {
super.initState();
loadUsers();
}
Future<void> loadUsers() async {
final data = await dbHelper.getAllUsers();
setState(() {
users = data.map((map) => User.fromMap(map)).toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Users')),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
),
);
}
}
🔹 Best Practices
- Singleton Pattern: Use one database instance
- Use Transactions: For multiple related operations
- Parameterized Queries: Prevent SQL injection
- Close Database: When app is terminated
- Version Control: Handle database migrations properly