Persisting data using HiveDB in Flutter

- 👤 Andrés Cruz

🇪🇸 En español

If you're looking for a fast, efficient, and hassle-free way to store data locally in Flutter, HiveDB is probably one of the best options. Personally, I use it when I need to persist simple data or small lists without having to set up a complex database like the SQFlite with Flutter setup we discussed earlier. HiveDB has a very straightforward key-value API, making it ideal for those of us who want frictionless "save and retrieve" functionality.

HiveDB, along with SharedPreferences that we covered in a previous post, is one of the popular ways we have to persist data in our Flutter application. HiveDB has a simple API for storing and fetching data, as we will see in this post.

What is HiveDB and When to Use it in Flutter

HiveDB is a local NoSQL database, optimized for Flutter and written in Dart. Although it is sometimes compared to SharedPreferences, Hive can store virtually any data type: integers, strings, maps, and even typed models (if you use adapters).

Why It's Popular Compared to SharedPreferences

When I first started with Hive, what attracted me most was how simple it was to store entire maps. With SharedPreferences, everything ends up being reduced to strings and basic types, so Hive is perfect when you need to save slightly more complex structures without converting anything.

Real Advantages and Limitations (including Isar)

Advantages:

  • Very fast (uses binary storage).
  • Works offline.
  • Suitable for small or medium lists.
  • Does not require SQL.
  • Ideal for settings, custom lists, favorites, etc.

Limitations:

  • It loads the entire "box" into memory, so don't use it for thousands of records.
  • For complex models, you need to generate adapters.
  • The community comments that Isar may be better for large volumes or more advanced queries.
  • Even so, when the logic is simple, Hive remains an excellent option, and in my experience, it never gave me problems except when I forgot to initialize it (and believe me, that error appears quite often).

Installation and Initialization of HiveDB in Flutter

Let's start by adding the dependency to our file:

`pubspec.yaml`

dependencies: 
    hive:
    hive_flutter:

Now, we need to initialize it. For that, we add the following line of code in `main.dart`:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Hive.initFlutter();
  runApp(ProviderScope(child: MyApp()));
}

This is more or less the typical code we use when initializing asynchronous processes at the application level, and we initialize Hive with `Hive.initFlutter()`.

As we will see in the next section, Hive works with the key-value scheme, where the value can be a primitive or a map.

Create Basic Structure in Hive

Just like with sharedpreferences, we must create a structure with which we can manage persistent data. In Hive, where we store the data is known as "boxes," which have a name for tracking and with which we get and set data:

class MyListService {
  static MyListService? _instance;
  final String boxName = 'myList';
  MyListService._();
  static MyListService get instance {
    if (_instance == null) {
      _instance = WatchlistService._();
    }
    return _instance!;
  }
}

Opening and Managing Boxes

With the structure above, we create a single instance that we access to manage our data. The next step is to define the methods for storing data. This first method allows creating a new record for an item or updating it if the ID exists:

Future<void> addToMyList(int id, Map<String, 
    dynamic> item) async {
  final box = await Hive.openBox<Map<String, 
      dynamic>>(boxName);
  if (box.get(id) == null) {
    box.put(id, item);
  }
}

The code above opens the box so we can administer it, in this case, to put the item using the ID.

To remove an item from Hive, we have:

Future<void> removeFromMyList(int id) async {
  final box = await Hive.openBox(boxName);
  box.delete(id);
}

Also, we can create a method that checks if an item is in the list using the ID:

Future<bool> isInMyList(int id) async {
  final box = await Hive.openBox(boxName);
  return box.containsKey(id);
}

Working with Key-Value and Maps

Hive works great with maps. I usually save my elements like this:

Future<void> addToMyList(int id, Map<String, dynamic> item) async {
 final box = await Hive.openBox<Map<String, dynamic>>(boxName);
 if (box.get(id) == null) {
   box.put(id, item);
 }
}

Finally, we have a method to get all the data from the list:

Future<Iterable<Map<String, dynamic>>> geMylist() async {
  Final box = await Hive.openBox<Map<String, 
      dynamic>>(boxName);
  return box.values;
}

I almost always initialize HiveDB in `main()` when starting the app:

void main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Hive.initFlutter();
 runApp(MyApp());
}

Optional: Create the Base Structure: Boxes and Service to Handle Data

Also, you can use a Singleton structure to centralize all access:

My Singleton structure for data access

class MyListService {
 static MyListService? _instance;
 final String boxName = 'myList';
 MyListService._();
 static MyListService get instance {
   _instance ??= MyListService._();
   return _instance!;
 }
}

Complete CRUD with HiveDB (with practical examples)

Create or update an item

Future<void> addToMyList(int id, Map<String, dynamic> item) async {
 final box = await Hive.openBox<Map<String, dynamic>>(boxName);
 box.put(id, item); // put sirve para crear o sobrescribir
}

Read individual data and lists

Future<Map<String, dynamic>?> getItem(int id) async {
 final box = await Hive.openBox<Map<String, dynamic>>(boxName);
 return box.get(id);
}

Get all values:

Future<Iterable<Map<String, dynamic>>> getMyList() async {
 final box = await Hive.openBox<Map<String, dynamic>>(boxName);
 return box.values;
}

Check if an element exists

Future<bool> isInMyList(int id) async {
 final box = await Hive.openBox(boxName);
 return box.containsKey(id);
}

Delete items or clear the entire box

Future<void> removeFromMyList(int id) async {
 final box = await Hive.openBox(boxName);
 box.delete(id);
}

Best Practices Using HiveDB in Real Apps

When to use maps and when to use typed models

  • Maps: when you want simplicity and speed (I use it this way for small lists).
    • Typed models + adapters: if you want validations or more solid structures.
    • Avoiding common problems when opening boxes.
  • Always open the boxes only once per service.
  • Opening and closing multiple times within the widget tree can affect performance.
  • Efficient service management and data access
  • The Singleton structure I use allows for:

    • maintaining a single centralized access

    reducing code repetition

    • avoiding initialization errors

Common HiveDB Errors and How I Solve Them

  1. "You need to initialize Hive"
    1. Solution: Add `await Hive.initFlutter()` before `runApp`.
  2. "Box not found / Did you forget to openBox()?"
    1. Solution: Open the box before using it:
    2. `await Hive.openBox('myList');`
  3. `MissingPluginException` on real devices
    1. Solution: Reinstall the app.
  4. This has happened to me several times in debug mode.

HiveDB vs Other Alternatives (SharedPreferences and Isar)

When to choose each option

  • SharedPreferences

    • Simple configurations
    • Boolean flags

    Very small data

  • HiveDB
    • Lists, maps, and simple structures
    • Favorites, lists of IDs, dynamic configurations
    • Small or medium apps
  • Isar
    • Large volume of data
    • Advanced queries
    • Complex relationships

Conclusion

HiveDB remains a fast, clean, and efficient way to save local data in Flutter. In my experience, when I only need to persist small lists or maps, Hive gives me exactly what I'm looking for: speed and simplicity without complicating the architecture. And if you ever need more power, you can always make the jump to Isar or an SQL database.

Frequently Asked Questions about HiveDB in Flutter

  • Is Hive safe for sensitive data?
    • Yes, if you use encryption with `HiveAesCipher`.
  • Can I save lists or complex models?
    • Yes, lists work fine; for models, you must use adapters.
  • Will Hive remain compatible with Isar?
    • Hive v4 will use an Isar-based backend; interoperability will become increasingly greater.

These are only some methods you can create, but there are others you can define to your liking according to your needs.

One of the most interesting operations we can do is set up a payment gateway with Stripe and Flutter.

I agree to receive announcements of interest about this Blog.

HiveDB together with sharedpreferences is one of the ways we persist data in our application in Flutter; HiveDB has a simple API to store and obtain data as we will see in this post.

| 👤 Andrés Cruz

🇪🇸 En español