Hive for Local Database in Flutter: A Practical Guide
How Hive became the default key-value store for Flutter apps, what hive_ce changes, and when you should choose it over Isar, sqflite, or Drift.
Published on • October 8, 2026
AI Assistant

Every Flutter app needs somewhere to keep session tokens, onboarding flags, cached lists, and user preferences. For a long time the answer was shared_preferences, and then for most teams it became Hive — a pure-Dart key-value store built for Flutter.
Hive’s pitch is in its own description: a “lightweight and buzzing-fast key-value database made for Flutter and Dart.” No platform channels, no native setup, works on mobile, desktop, and web the same way.
Why Hive took over Flutter storage
The original shared_preferences stores everything as a string-keyed bag of primitives. That works for isOnboarded = true and falls apart the moment you want a typed object list.
Hive gives you:
- Typed boxes.
Box<Reminder>gives youReminderobjects, notMap<String, dynamic>. - Zero platform channels. Pure Dart — identical behavior on Android, iOS, Windows, Linux, macOS, and web/WASM.
- Speed. Binary serialization (
hiveuses its own TypeAdapters) with lazy reads. - Reactive reads.
box.watch()emits a stream of changes, so widgets can rebuild on writes. - No build step required for basic use. TypeAdapters can be written by hand or generated.
A minimal setup:
import 'package:hive_flutter/hive_flutter.dart';
class Reminder {
Reminder(this.title, this.done);
final String title;
bool done;
}
Future<void> main() async {
await Hive.initFlutter();
Hive.registerAdapter(ReminderAdapter());
final box = await Hive.openBox<Reminder>('reminders');
runApp(MyApp(box: box));
}
Reading and writing is synchronous — that is the feature most people notice first:
box.put('r1', Reminder('Buy milk', false));
final r = box.get('r1'); // Reminder, no await
Because put returns synchronously in the classic API, Hive is exceptionally ergonomic for optimistic UI updates.
The 2026 landscape: hive and hive_ce
Hive’s maintenance story changed. The original repository lives under the isar GitHub org, and community attention moved to hive_ce — a community edition fork that continues the package under a new name.
What hive_ce brings to the table (per its pub.dev listing):
- A Hive CE Inspector DevTools extension for browsing box contents while the app runs
- Isolate support through
IsolatedHivefor background access - Flutter web WASM support
- Ongoing maintenance independent of the original package’s status
If you are starting a new project in 2026, evaluate hive_ce alongside classic hive before committing. The API is intentionally close, so migration is mostly a dependency rename plus a codegen invocation.
dependencies:
hive_flutter: ^1.1.0
dev_dependencies:
hive_ce_generator: any
build_runner: any
dart run build_runner build --delete-conflicting-outputs
When Hive is the right choice
Hive is a key-value store, not a relational database. It shines when:
- You are caching API responses as opaque objects
- You need fast synchronous reads in
build()methods - Your data model is documents or records with stable IDs
- You want one storage solution across all platforms including web WASM
- You are persisting app state that a state-management layer (Riverpod, Bloc) already models
It is a poor fit when you need ad-hoc queries, joins, migrations across complex schemas, or relational integrity.
Hive vs. the alternatives
The Flutter local database space in 2026 generally weighs three heavyweights — Hive, Isar, and SQLite (via sqflite or Drift) — plus a long tail.
Isar is the spiritual successor to Hive for relational-ish NoSQL: composite and multi-entry indexes, full-text search, ACID semantics, and query watchers. The official repo warns that “Isar v4 is not ready for production use — if you want to use Isar in production, please use the stable version 3.” Community forks (isar-community) maintain the v3 line. Choose Isar when you need real queries over object collections.
Drift is a reactive persistence library built on SQLite, and a Flutter Favorite. It markets itself as flexible (SQL and Dart queries), type-safe, and “the only major persistence library with builtin threading support, allowing you to run database code across isolates with zero additional effort.” Choose Drift when you need SQL, migrations, joins, and a schema that will grow.
sqflite is the thin wrapper over SQLite. Choose it when you want raw SQL control with minimal abstraction.
| Concern | Hive | Isar | Drift | sqflite |
|---|---|---|---|---|
| Model | Key-value | NoSQL documents | Relational | Relational |
| Query language | Get by key, watch | Typed filter chains | SQL or Dart | SQL |
| Web/WASM | Yes (hive_ce) | Limited | Yes | No |
| Codegen | Optional adapters | Required | Required | None |
| Typical use | Cache, prefs, state | Searchable collections | Complex domain data | Raw SQL |
A common production pattern is both: Hive (or shared_preferences) for flags and tokens, Drift for the domain model.
Practical patterns
Watch and rebuild.
Stream<List<Reminder>> watchReminders(Box<Reminder> box) =>
box.watch().map((_) => box.values.toList());
Wire that into a StreamBuilder or a Riverpod StreamProvider and every write updates the UI.
Keep objects immutable. Hive stores whatever you hand it. Mutating an object already in a box does not persist the change — you must put it again. Immutable models plus explicit writes prevent a whole category of “my edit didn’t save” bugs.
Namespace your boxes. One box per feature (settings, reminders, cache:v1) beats one giant box, both for performance and for the ability to deleteFromDisk() a single feature’s data.
Version your cache, not your schema. Store a schemaVersion key and clear the box on mismatch rather than writing migrations for cached API data.
Respect platform limits. On web, Hive writes to browser storage; large boxes will hit quota. Move bulky data to IndexedDB-backed stores or keep caches bounded.
Do not put secrets in plain Hive. Box files are unencrypted by default. Hive supports encryption with a 256-bit key, but for API keys and tokens prefer flutter_secure_storage, which delegates to Keychain/Keystore.
Testing with Hive
Hive is unusually test-friendly because it is pure Dart:
setUp(() async {
Hive.init('./test_tmp');
box = await Hive.openBox<TestBox>('test');
});
tearDown(() async {
await Hive.deleteFromDisk();
});
No emulator, no platform channels, no TestWidgetsFlutterBinding needed for storage tests. Use Hive.init(tempDir) to isolate test runs, and remember that IsolatedHive spawns real isolates — prefer the plain Hive in unit tests for speed.
Migrating away from hard-coded keys
The most common Hive smell is string-key access scattered across the codebase:
// Fragile — typo surfaces at runtime
box.get('user_name');
Centralize access behind a typed repository:
class SettingsRepo {
SettingsRepo(this._box);
final Box<Settings> _box;
static const _k = 'settings';
Settings get value => _box.get(_k) ?? const Settings();
set value(Settings s) => _box.put(_k, s);
Stream<Settings> watch() =>
_box.watch(key: _k).map((_) => value);
}
Now the storage layer has one seam, and swapping Hive for Drift later touches exactly one file.
Wrapping up
Hive earned its place in Flutter by being fast, pure Dart, and genuinely cross-platform. In 2026 the decision is less “Hive vs. nothing” and more “Hive vs. Isar vs. Drift” — pick Hive for caches and app state, Isar for queryable object collections, and Drift when your data is relational and will outlive the app version.
References
- hive_ce package — community edition with DevTools inspector, isolates, and WASM support
- Hive repository
- Isar repository
- drift package
- sqflite package
- Flutter persistence docs