Hive CE NoSQL Database Guide
Goal
Implement high-performance NoSQL object storage using Hive CE (Community Edition). Hive offers blazing-fast synchronous operations, custom type adapters, and lazy loading for efficient local data persistence.
Process
Phase 1: Install Dependencies
dependencies:
hive_ce: ^2.19.3
hive_ce_flutter: ^2.3.4
dev_dependencies:
hive_ce_generator: ^1.11.1
build_runner: ^2.14.1
Phase 2: Initialize Hive
import 'package:hive_ce_flutter/hive_ce_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
// Register adapters
Hive.registerAdapter(UserAdapter());
Hive.registerAdapter(TodoAdapter());
// Open boxes
await Hive.openBox<User>('users');
await Hive.openBox<Todo>('todos');
runApp(MyApp());
}
Phase 3: Define Models with TypeAdapters
Using Code Generation (Recommended):
import 'package:hive_ce/hive.dart';
part 'user.g.dart';
@HiveType(typeId: 0)
class User extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String name;
@HiveField(2)
final String email;
@HiveField(3)
final DateTime createdAt;
User({
required this.id,
required this.name,
required this.email,
required this.createdAt,
});
}
// Generate adapter: flutter pub run build_runner build
Manual TypeAdapter:
class UserAdapter extends TypeAdapter<User> {
@override
final int typeId = 0;
@override
User read(BinaryReader reader) {
return User(
id: reader.readString(),
name: reader.readString(),
email: reader.readString(),
createdAt: DateTime.fromMillisecondsSinceEpoch(reader.readInt()),
);
}
@override
void write(BinaryWriter writer, User obj) {
writer.writeString(obj.id);
writer.writeString(obj.name);
writer.writeString(obj.email);
writer.writeInt(obj.createdAt.millisecondsSinceEpoch);
}
}
Phase 4: CRUD Operations
Create/Update:
final box = Hive.box<User>('users');
// Add with auto-key
await box.add(User(id: '1', name: 'John', email: 'john@example.com', createdAt: DateTime.now()));
// Put with custom key
await box.put('user_1', user);
// Update (if model extends HiveObject)
user.name = 'Jane';
await user.save();
Read:
// Get by key
final user = box.get('user_1');
// Get all values
final allUsers = box.values.toList();
// Filter
final activeUsers = box.values.where((u) => u.isActive).toList();
// Get at index
final firstUser = box.getAt(0);
Delete:
// Delete by key
await box.delete('user_1');
// Delete at index
await box.deleteAt(0);
// Delete if model extends HiveObject
await user.delete();
// Clear all
await box.clear();
Phase 5: Advanced Patterns
Lazy Boxes (for large data):
// Open lazy box (loads data on demand)
final lazyBox = await Hive.openLazyBox<User>('users_lazy');
// Async get (only loads when accessed)
final user = await lazyBox.get('user_1');
Encrypted Boxes:
import 'package:hive_ce/hive.dart';
import 'dart:convert';
import 'dart:typed_data';
final key = Hive.generateSecureKey(); // Store this securely!
final encryptedBox = await Hive.openBox<User>(
'secure_users',
encryptionCipher: HiveAesCipher(key),
);
Reactive Listening:
// Listen to box changes
box.watch().listen((event) {
print('Box changed: ${event.key}');
if (event.deleted) {
print('Item deleted');
} else {
print('Item added/updated: ${event.value}');
}
});
// Listen to specific key
box.watch(key: 'user_1').listen((event) {
print('User 1 updated: ${event.value}');
});
Compaction (reduce file size):
// Compact box to reclaim space
await box.compact();
// Auto-compact on close
await box.close();
Phase 6: Integration with State Management
With Riverpod:
final userBoxProvider = Provider<Box<User>>((ref) {
return Hive.box<User>('users');
});
final usersProvider = StreamProvider<List<User>>((ref) {
final box = ref.watch(userBoxProvider);
return box.watch().map((_) => box.values.toList());
});
// Usage in widget
final users = ref.watch(usersProvider);
users.when(
data: (list) => ListView(children: list.map((u) => UserTile(u)).toList()),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
Constraints
- TypeId Uniqueness: TypeIds must be unique across all models (0-223 for user types).
- Schema Evolution: Adding fields is safe. Removing fields requires migration logic.
- Synchronous by Default: Most operations are sync. Use lazy boxes for large data.
- No Relations: Hive is NoSQL. Store object references (IDs) manually.
- Close Boxes: Always close boxes when no longer needed to free resources.
- Backup Key: For encrypted boxes, ALWAYS backup the encryption key securely.