Flutter hive vs shared preferences : Which one to choose?

When developing Flutter applications, storing data locally is often necessary for various reasons, such as caching user preferences, managing app state, or persisting data offline. Flutter provides several options for local data storage, with SharedPreferences and Hive being two popular choices. This blog post will compare Hive and SharedPreferences, highlighting their differences, advantages, and disadvantages, to help you choose the right one for your project.

Introduction to SharedPreferences

SharedPreferences is a simple storage solution that allows you to store key-value pairs of primitive data types: booleans, integers, doubles, and strings. It is suitable for storing small amounts of simple data like user preferences, settings, or flags.

Introduction to Hive

Hive is a lightweight, NoSQL database written in pure Dart. It is designed to be fast, easy to use, and fully cross-platform, supporting mobile, desktop, and web. Hive allows you to store more complex data structures and offers features like encryption and lazy loading.

Key Differences

Here’s a comparison table highlighting the key differences between SharedPreferences and Hive:

Feature SharedPreferences Hive
Data Types Primitives (bool, int, double, String) Any Dart object (supports custom classes)
Data Size Small amounts of simple data Larger and more complex data
Performance Synchronous, can cause UI blocking Asynchronous, non-blocking UI
Complexity Very simple to use More features, slightly more complex
Storage Format XML (on Android) or Plist (on iOS) Binary format
Queries Not supported Supported through indexes
Encryption Not supported by default Built-in support for encryption

When to Use SharedPreferences

SharedPreferences is ideal when:

  • You need to store a small amount of primitive data.
  • Simplicity and ease of use are more important than performance or data complexity.
  • Data doesn’t need to be queried or indexed.
  • Encryption is not a requirement.

Example of Using SharedPreferences

First, add the shared_preferences package to your pubspec.yaml:

dependencies:
  shared_preferences: ^2.2.2

Then, use SharedPreferences to save and retrieve data:

import 'package:shared_preferences/shared_preferences.dart';

class SharedPreferencesService {
  static Future saveString(String key, String value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(key, value);
  }

  static Future getString(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(key);
  }

  static Future saveBool(String key, bool value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(key, value);
  }

  static Future getBool(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getBool(key);
  }

  static Future remove(String key) async {
      final prefs = await SharedPreferences.getInstance();
      prefs.remove(key);
  }
}

// Usage
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await SharedPreferencesService.saveString('username', 'johndoe');
  String? username = await SharedPreferencesService.getString('username');
  print('Username: $username'); // Output: Username: johndoe

  await SharedPreferencesService.saveBool('isDarkMode', true);
  bool? isDarkMode = await SharedPreferencesService.getBool('isDarkMode');
  print('Is Dark Mode: $isDarkMode'); // Output: Is Dark Mode: true
}

When to Use Hive

Hive is ideal when:

  • You need to store larger amounts of data or complex objects.
  • Performance is critical.
  • You need to query or index your data.
  • Encryption is required for sensitive data.
  • You want a solution that supports desktop and web in addition to mobile.

Example of Using Hive

First, add the hive and hive_flutter packages to your pubspec.yaml:

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.2

And add build_runner and hive_generator to your dev_dependencies for code generation:

dev_dependencies:
  build_runner: ^2.4.8
  hive_generator: ^2.0.1

Create a Hive object (requires type adapter. We are going to generate this) :

import 'package:hive/hive.dart';

part 'user.g.dart';

@HiveType(typeId: 0)
class User {
  @HiveField(0)
  String name;

  @HiveField(1)
  int age;

  @HiveField(2)
  String email;

  User({required this.name, required this.age, required this.email});
}

Run flutter pub run build_runner build in the terminal to generate type adapter: user.g.dart file. Don’t forget to import this in wherever you want to use your Hive model.

Then, use Hive to save and retrieve data:

import 'package:flutter/widgets.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'user.dart'; // generated user model

class HiveService {

  static Future initializeHive() async {
      await Hive.initFlutter();
      Hive.registerAdapter(UserAdapter());
  }
  static Future saveUser(User user) async {
    var box = await Hive.openBox('usersBox');
    await box.put(user.email, user);
  }

  static Future getUser(String email) async {
    var box = await Hive.openBox('usersBox');
    return box.get(email);
  }

  static Future deleteUser(String email) async {
    var box = await Hive.openBox('usersBox');
    await box.delete(email);
  }

  static Future> getAllUsers() async {
        var box = await Hive.openBox('usersBox');
        return box.values.toList();
  }

  static Future clearAllUsers() async {
        var box = await Hive.openBox('usersBox');
        await box.clear();
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await HiveService.initializeHive();

  // Usage
  final user = User(name: 'John Doe', age: 30, email: 'john.doe@example.com');
  await HiveService.saveUser(user);

  User? retrievedUser = await HiveService.getUser('john.doe@example.com');
  print('Retrieved User: ${retrievedUser?.name}, ${retrievedUser?.age}, ${retrievedUser?.email}');
// Retrieved User: John Doe, 30, john.doe@example.com
  await HiveService.clearAllUsers();
}

Pros and Cons

SharedPreferences

  • Pros:
    • Very simple and easy to use.
    • Suitable for small amounts of data.
  • Cons:
    • Only supports primitive data types.
    • Synchronous, can cause UI blocking.
    • No built-in encryption.

Hive

  • Pros:
    • Supports any Dart object.
    • Asynchronous, non-blocking operations.
    • Built-in encryption.
    • Supports indexes and queries.
    • Cross-platform support (mobile, desktop, web).
  • Cons:
    • More complex to set up than SharedPreferences.
    • Larger dependency size compared to SharedPreferences.

Conclusion

Choosing between SharedPreferences and Hive depends on the requirements of your Flutter application. If you need to store small amounts of simple data and prioritize ease of use, SharedPreferences is a good choice. However, if you need to store larger amounts of complex data, require better performance, or need features like encryption and querying, Hive is the more suitable option.

By understanding the strengths and limitations of each solution, you can make an informed decision that optimizes your app’s performance and data management.