If you're building offline-first in Flutter, sooner or later you have to pick a local storage engine. I've used all three of these in production apps, and each one has a real trade-off — here's how I'd actually decide between them.
Quick overview
| Hive | Isar | SQLite (sqflite) | |
|---|---|---|---|
| Type | NoSQL key-value | NoSQL object database | Relational (SQL) |
| Query Power | Basic | Strong (indexes, filters, sorting) | Full SQL |
| Setup Complexity | Very Low | Low-medium | Medium |
| Speed (simple reads/writes) | Very Fast | Very Fast | Fast, but slower for simple ops |
| Best for | Simple key-value data, settings, small datasets | Structured objects with queries, medium-large datasets | Complex relational data, joins, existing SQL knowledge |
Hive — when simplicity wins
Hive (the Flutter package, not the blockchain — easy to confuse if you're active on both like I am) is essentially a fast, lightweight key-value store. No query engine, no schema migrations to worry about. It shines when your data doesn't need complex querying — user preferences, cached API responses, simple lists.
dart var box = await Hive.openBox('tasks'); box.put('task1', Task(title: 'Buy milk', done: false)); var task = box.get('task1');
The catch: once your data model gets more relational (tasks that belong to projects that belong to users, with filtering across all of it), you'll feel Hive's limits fast.
Isar — the middle ground that often wins
Isar gives you Hive-like speed with actual query capabilities: indexes, filters, sorting, even full-text search. For most offline-first apps I build now, this is my default. It handles the "I need structured data AND I need to query it" problem without the overhead of full SQL.
dart
final tasks = await isar.tasks
.filter()
.doneEqualTo(false)
.sortByCreatedAtDesc()
.findAll();
The trade-off is a slightly steeper setup (code generation via build_runner) and it's a newer project than SQLite, so the ecosystem and community answers are thinner if you hit an edge case.
SQLite — when you actually need relational data
If your data genuinely has complex relationships — multiple tables, joins, aggregate queries — SQLite via sqflite is still the most battle-tested option. It's not Flutter-specific, so any SQL knowledge you already have transfers directly, and debugging tools are mature.
dart
final db = await openDatabase('app.db');
final tasks = await db.rawQuery(
'SELECT * FROM tasks WHERE done = 0 ORDER BY created_at DESC'
);
The cost is more boilerplate — you're writing migrations, managing schema versions, and SQL strings are less type-safe than Isar's query builder unless you add an ORM layer on top.
My actual decision rule
Small, flat data (settings, cache, single-entity lists) → Hive
Structured data that needs filtering/sorting but isn't deeply relational → Isar
Genuinely relational data, or you're porting from a backend that's already SQL → SQLite
I default to Isar for most new offline-first apps at this point — it hits the sweet spot between Hive's simplicity and SQLite's query power without dragging in the full weight of a relational database.
What's your default pick, and has it changed as your apps got more complex? Curious if others have landed somewhere different.