Flutter, Google’s UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase, offers various options for data storage. While relational databases are a common choice, NoSQL databases like Hive and Isar provide compelling alternatives for fast and efficient local data storage, especially in scenarios requiring high performance and flexible data schemas.
What are NoSQL Databases?
NoSQL databases (Not Only SQL) are non-relational databases that provide a mechanism for storage and retrieval of data that is modeled in means other than the tabular relations used in relational databases. NoSQL databases are schema-less, support easy replication, and have a simple API. Some common types include document stores, key-value stores, and graph databases.
Why Choose NoSQL for Flutter?
- Performance: NoSQL databases are optimized for fast reads and writes, making them suitable for applications needing quick data access.
- Flexibility: They support schema-less or flexible schemas, making it easier to handle evolving data requirements.
- Scalability: Designed for horizontal scalability, ideal for applications that anticipate growing data volumes.
Hive: Lightweight Key-Value Database for Flutter
What is Hive?
Hive is a lightweight and fast key-value database written in pure Dart. It’s designed for simple use cases where speed and simplicity are critical.
Key Features of Hive
- Fast: Hive is incredibly fast due to its efficient storage format and Dart implementation.
- Simple: It provides a simple and easy-to-use API, ideal for developers new to local data storage.
- No Native Dependencies: Being written in Dart, Hive works seamlessly on all platforms Flutter supports without requiring native dependencies.
- Encryption: Supports encryption to protect sensitive data.
Implementing Hive in Flutter
Step 1: Add Dependency
Add the Hive and Hive Generator dependencies to your pubspec.yaml
file:
dependencies:
hive: ^2.0.0
hive_flutter: ^1.0.0
dev_dependencies:
hive_generator: ^1.0.0
build_runner: ^2.0.0
Step 2: Initialize Hive
Initialize Hive in your main.dart
file:
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter('hive_db'); // Optional: Specify a sub-directory
// Register adapters if necessary
runApp(MyApp());
}
Step 3: Define Data Model
Create a Dart class to represent your data model. Annotate the class and its fields to generate Hive adapters.
import 'package:hive/hive.dart';
part 'my_data_model.g.dart'; // This line is important for code generation
@HiveType(typeId: 0)
class MyDataModel {
@HiveField(0)
String name;
@HiveField(1)
int age;
MyDataModel({required this.name, required this.age});
}
Run the build runner to generate the Hive adapter:
flutter pub run build_runner build
Step 4: Open a Hive Box
Open a Hive box to read and write data:
import 'package:hive/hive.dart';
import 'my_data_model.dart';
class HiveService {
static const String myDataBoxName = 'myDataBox';
Future addData(MyDataModel data) async {
final box = await Hive.openBox(myDataBoxName);
await box.add(data);
}
Future> getAllData() async {
final box = await Hive.openBox(myDataBoxName);
return box.values.toList();
}
}
Step 5: Use the Hive Service in your Flutter App
import 'package:flutter/material.dart';
import 'package:hive_example/hive_service.dart';
import 'package:hive_example/my_data_model.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final HiveService _hiveService = HiveService();
List _dataList = [];
@override
void initState() {
super.initState();
_loadData();
}
Future _loadData() async {
_dataList = await _hiveService.getAllData();
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: _dataList.length,
itemBuilder: (context, index) {
final data = _dataList[index];
return ListTile(
title: Text(data.name),
subtitle: Text('Age: ${data.age}'),
);
},
),
);
}
}
Isar: Ultra-Fast Object Database for Flutter
What is Isar?
Isar is an ultra-fast, scalable, and easy-to-use NoSQL object database for Flutter. It’s designed to be both developer-friendly and performant, making it ideal for complex applications needing fast data access.
Key Features of Isar
- High Performance: Isar is optimized for speed and supports asynchronous operations for non-blocking UI.
- Developer-Friendly: Offers a simple API and efficient query language.
- Type-Safe: Ensures type safety with code generation, reducing runtime errors.
- Cross-Platform: Works on Android, iOS, and desktop platforms.
Implementing Isar in Flutter
Step 1: Add Dependencies
Add the Isar and Isar Generator dependencies to your pubspec.yaml
file:
dependencies:
isar: ^3.0.0
isar_flutter_libs: any # Contains Isar Core libs suitable for Flutter
dev_dependencies:
isar_generator: ^3.0.0
build_runner: ^2.0.0
Step 2: Define Data Model
Create a Dart class to represent your data model and annotate it with Isar annotations.
import 'package:isar/isar.dart';
part 'my_isar_model.g.dart';
@collection
class MyIsarModel {
Id? id; // Isar requires an ID field, which is nullable
@Index()
late String name;
int age = 0;
}
Run the build runner to generate the Isar code:
flutter pub run build_runner build
Step 3: Initialize Isar
Initialize Isar in your main.dart
file:
import 'package:flutter/material.dart';
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
import 'my_isar_model.dart';
late Isar isar;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationDocumentsDirectory();
isar = await Isar.open(
[MyIsarModelSchema],
directory: dir.path,
inspector: true, // Enable the Isar Inspector for debugging
);
runApp(MyApp());
}
Step 4: Perform CRUD Operations
Use Isar to perform CRUD (Create, Read, Update, Delete) operations:
import 'package:isar/isar.dart';
import 'my_isar_model.dart';
class IsarService {
Future saveData(MyIsarModel data) async {
await isar.writeTxn(() async {
await isar.myIsarModels.put(data); // Insert & update
});
}
Future> getAllData() async {
return await isar.myIsarModels.where().findAll();
}
Future deleteData(int id) async {
await isar.writeTxn(() async {
await isar.myIsarModels.delete(id);
});
}
}
Step 5: Use the Isar Service in your Flutter App
import 'package:flutter/material.dart';
import 'package:isar_example/isar_service.dart';
import 'package:isar_example/my_isar_model.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final IsarService _isarService = IsarService();
List _dataList = [];
@override
void initState() {
super.initState();
_loadData();
}
Future _loadData() async {
_dataList = await _isarService.getAllData();
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: _dataList.length,
itemBuilder: (context, index) {
final data = _dataList[index];
return ListTile(
title: Text(data.name),
subtitle: Text('Age: ${data.age}'),
);
},
),
);
}
}
Comparison: Hive vs. Isar
Feature | Hive | Isar |
---|---|---|
Performance | Fast, lightweight | Ultra-fast, optimized |
Complexity | Simple, easy to use | More features, slightly more complex |
Dart Native | Yes, 100% Dart | Native dependencies |
Queries | Limited | Advanced query language |
Data Model | Key-value | Object database |
Encryption | Yes | Yes |
Conclusion
NoSQL databases like Hive and Isar offer powerful and efficient solutions for local data storage in Flutter applications. Hive is an excellent choice for simple use cases requiring fast performance and ease of use, while Isar provides advanced features and ultra-fast performance for more complex data storage needs. Choosing the right database depends on your application’s specific requirements, balancing simplicity, performance, and scalability.