Hive is a lightweight NoSQL storage for Flutter that works without native code. Unlike SQLite or Firebase, Hive does not require native library bindings and works exclusively through Dart. According to Pub.dev, 2024, Hive has been downloaded over 10 million times and is used in every third Flutter project that requires local data storage without server infrastructure.
Key Takeaways
Hive is a NoSQL database written entirely in Dart that requires no native libraries. It was created by Simon Leiter in 2019 as an alternative to SQLite for Flutter projects. Hive stores data in a binary .hive format optimized for fast reading and writing on mobile devices. The .hive format uses a custom serialization scheme where each data type has its own byte prefix, allowing file reading without prior schema knowledge — unlike Protocol Buffers or FlatBuffers.
The core idea of Hive is maximum simplicity. The database requires no native engine initialization, includes no SQL parser, and does not use reflection. All operations are direct Dart function calls with binary serialization through WriteBuffer and ReadBuffer.
According to the Flutter Community survey (2023), Hive is among the top 5 most used data storage packages in Flutter, second only to shared_preferences in popularity, but surpassing it in functionality and speed.
Hive uses the concept of a Box — analogous to a table in relational databases. Each Box is a file on disk containing a set of key-value pairs. The key can be int or String, the value can be any primitive type, list, Map, or a custom object via TypeAdapter. Boxes are isolated from each other and are opened independently.
Hive does not require platform channels. This means it works the same on Android, iOS, Web, macOS, Windows, and Linux without additional setup. For projects targeting web builds, Hive remains the only lightweight NoSQL solution — SQLite does not work in browsers. Hive uses IndexedDB as a backend for web, ensuring data persistence even in a browser environment.
Hive serializes data into binary format on write and deserializes on read. The internal mechanism is based on BinaryWriter and BinaryReader, which pack data into compact byte arrays. The storage size on disk is on average 2–3 times smaller than the JSON representation of the same data.
When opening a Box, Hive loads the entire file into RAM. This provides high read speed (microseconds) but imposes a size limitation: it is recommended to store no more than 50–100 MB per Box. For larger volumes, use LazyBox — lazy loading of records from disk.
Hive works single-threaded within a Dart isolate. Write operations are performed synchronously with file locking. For asynchronous access, use Hive.openBox() with await. Concurrent access from multiple isolates is not directly supported — a separate synchronization mechanism is required.
Hive occupies a niche between SharedPreferences and SQLite. It is more complex than SharedPreferences (supports custom objects) but simpler than SQLite (no SQL queries required). Let us compare the key characteristics.
| Characteristic | Hive | SharedPreferences | SQLite |
|---|---|---|---|
| Data types | Any (via TypeAdapter) | Primitives only | SQL types |
| Read speed | ~30,000 ops/s | ~5,000 ops/s | ~2,000 ops/s |
| Native code | Not required | Required (Android) | Required |
| Web support | Yes | No | No |
| Complexity | Low | Minimal | Medium |
| Reactivity | WatchBox | No | Via ORM |
Hive is optimal for small volumes of data: app settings, API response cache, local sync queue, favorites, and browsing history. If the data does not exceed 50 MB and does not require relational queries — Hive is faster and simpler than SQLite.
Hive does not support queries with filtering by multiple fields, JOIN, or aggregate functions. If you need complex queries like “select all tasks for today with priority above 3” — use SQLite with drift or floor. Hive is also not suitable for storing more than 100 MB of data due to loading into memory.
Hive starts with initialization and opening a Box. Below are basic operations for a typical scenario — storing a task list in a Flutter application. All examples work without native platform calls.
Before using Hive, you must call Hive.initFlutter() in the main function. Then open a Box via Hive.openBox() — the result will be a Box instance ready for reading and writing.
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void async main() {
await Hive.initFlutter();
final settingsBox = await Hive.openBox('settings');
runApp(MyApp());
}
Box provides put, get, delete methods and an iterator for traversing all entries. Keys and values are typed via generics — by default Box<dynamic> accepts any type, but it is recommended to specify a concrete type.
// Write data
final box = await Hive.openBox<String>('tasks');
await box.put('task_1', 'Buy groceries');
// Read
final task = box.get('task_1');
// All keys
final allTasks = box.values.toList();
// Delete
await box.delete('task_1');
// Clear Box
await box.clear();
WatchBox is an extension of Box that notifies subscribers of changes. In Flutter, this integrates with ValueListenableBuilder: when any value in the Box changes, the widget rebuilds automatically without calling setState.
final watchBox = await Hive.openBox('settings');
// In the widget
ValueListenableBuilder(
valueListenable: watchBox.listenable(),
builder: (context, box, _) {
final counter = box.get('counter') ?? 0;
return Text('Counter: $counter');
},
)
TypeAdapter is Hive's mechanism for serializing custom Dart objects. The adapter describes how to convert an object to binary format (write) and back (read). Unlike json_serializable, TypeAdapter does not require reflection and is faster.
The adapter implements the TypeAdapter
// Data model
class Task {
final String title;
final bool isCompleted;
Task({required this.title, this.isCompleted = false});
}
// TypeAdapter
class TaskAdapter extends TypeAdapter<Task> {
@override
final int typeId = 0;
@override
Task read(BinaryReader reader) {
return Task(
title: reader.readString(),
isCompleted: reader.readBool(),
);
}
@override
void write(BinaryWriter writer, Task obj) {
writer.writeString(obj.title);
writer.writeBool(obj.isCompleted);
}
}
For projects with a large number of models, Hive provides hive_generator and build_runner. The @HiveType annotation on the class and @HiveField on fields generate the adapter automatically. This is convenient when the model has 10+ fields — manual read/write becomes tedious.
Hive reads from memory rather than disk, providing speeds of up to 30,000 operations per second. For optimization: open a Box once and reuse it throughout the app, do not call openBox repeatedly. Use Hive.box() (synchronous getter) after initialization — it returns an already opened Box without creating a new instance.
Hive integrates easily with popular Flutter state managers. For Provider, use ChangeNotifierProvider that reads data from the Box on initialization and updates via listenable. For Riverpod, a StreamProvider subscribed to WatchBox works well. This combination provides reactive UI updates on every data change in Hive without manual setState calls. In a typical Flutter project, such architecture allows synchronizing state between screens without a global singleton.
Frequently Asked Questions
Hive works on pure Dart, so it can be used in any Dart project: server-side (Dart VM), console, or AngularDart. For Flutter, hive_flutter is additionally required for storage path initialization.
Hive supports AES-256 encryption through the encryptionKey parameter when opening a Box. The key must be a 32-byte string. An encrypted Box cannot be read without the key — data is protected at the file level.
Isar is the successor to Hive by the same author (Simon Leiter). Isar is faster, supports indexes, relationships, and complex queries. However, Hive remains relevant for simple scenarios where Isar's relational capabilities are not needed, and for projects where minimal dependencies are important.
Hive does not have built-in migrations. If the TypeAdapter structure changes, old data will not deserialize. Solution: increase the adapter's typeId and write a manual migration in code, or use delete for the old key before writing a new one.
Hive loads the Box entirely into memory. The recommended limit is 50–100 MB per Box. Exceeding this may cause delays when opening the Box and increased RAM consumption. For larger volumes, use multiple Boxes or LazyBox with lazy loading.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also