Flutter Local Storage: SharedPreferences vs Hive vs sqflite (Which Should You Use?)

Picking the wrong local storage option in Flutter means rewriting your data layer later — sometimes completely. It’s one of those architecture decisions that feels small at the start and becomes expensive if you get it wrong.

The good news: Flutter has exactly three mainstream options, and each has a clear use case. SharedPreferences for simple settings. Hive for offline object storage without SQL. sqflite for structured, relational data that needs querying. The hard part is knowing which situation you’re in — and that’s exactly what this post settles.

🚨 Important 2026 update: Hive maintenance warning
The original hive and hive_flutter packages are no longer actively maintained by their original author. The community created hive_ce (Community Edition) as a maintained fork. If you’re starting a new project in 2026, use hive_ce — not the original hive. This post covers both where relevant, and all Hive code examples use the hive_ce API.
📋 Prerequisites

1. Quick Answer: The Comparison Table

If you’re in a hurry, this table gives you the answer. The rest of the post backs it up with code and explanation:

Attribute SharedPreferences Hive (hive_ce) sqflite
Storage modelKey-value (primitives only)Key-value (any Dart object)Relational SQL tables
Data typesint, double, bool, String, List<String>Primitives + custom objects via TypeAdapterAnything (stored as Maps)
Setup complexity⭐ Minimal⭐⭐ Moderate (code gen)⭐⭐⭐ Most involved
SQL requiredNoNoYes
Querying / filteringNoneManual iterationFull SQL WHERE / JOIN
RelationshipsNoNoYes (JOINs, foreign keys)
EncryptionNo (use flutter_secure_storage)Yes (AES-256 built-in)No (use SQLCipher)
Platform supportAll (incl. Web)All (incl. Web, pure Dart)Android/iOS/macOS + FFI for others
PerformanceFast (simple ops)Very fast (cached reads)Moderate
Maintenance✅ Official Flutter team⚠️ Community fork (hive_ce)✅ Actively maintained
Best forApp settings, flags, prefsCaching, offline lists, objectsComplex structured data at scale

2. Decision Flowchart — Pick in 30 Seconds

🔀 Which local storage do I need?
Do you need to store more than primitives (int, bool, String)?
↓ NO — just simple settings/flags
✅ Use SharedPreferences — theme, login state, onboarding flag


↓ YES — need to store objects or lists
Do your objects have relationships (e.g. users → orders, students → records)?
↓ NO — objects are self-contained
Do you need to query/filter with complex conditions?
↓ NO — simple list of items
✅ Use Hive (hive_ce) — notes, chat cache, shopping cart, user profile


↓ YES — need filtering/sorting
⚠️ Hive can work (manual iteration) or consider sqflite


↓ YES — need JOINs or foreign keys
✅ Use sqflite — inventory, finance, attendance, any relational data

3. SharedPreferences: App Settings and Simple Flags

SharedPreferences wraps platform-native key-value storage: NSUserDefaults on iOS/macOS, SharedPreferences on Android, and LocalStorage on Web. It is published by the official Flutter team (flutter.dev) and has over 10,500 likes on pub.dev. It is the right tool for one specific job: storing small primitive values that represent user preferences or app state.

✅ Use SharedPreferences when:
  • You’re storing a dark mode preference (bool)
  • You’re tracking whether the user has seen the onboarding screen (bool)
  • You’re saving the selected language code (String)
  • You’re storing a simple counter or score (int)
  • You need the simplest possible setup with no boilerplate

Setup

The Three APIs (Important for 2026)

As of v2.3.0+, SharedPreferences has three distinct APIs. Most tutorials still show the legacy one — here’s what they all are and which to use:

Loading in initState — The Standard Flutter Pattern

🚨 Never store sensitive data in SharedPreferences
Auth tokens, passwords, API keys, and personal health or financial data must NOT go in SharedPreferences — it stores everything in plaintext and has no write-persistence guarantee. Use flutter_secure_storage for sensitive values instead.

4. Hive (hive_ce): Offline Object Storage Without SQL

Hive is a lightweight, fast, pure-Dart NoSQL database that stores data in binary format. Unlike SharedPreferences it handles full Dart objects — lists, custom models, nested structures. Data is organised in Boxes (think: named containers). It requires no SQL knowledge and runs on every platform including Web.

⚠️ Use hive_ce, not hive
The original hive package is unmaintained. Add hive_ce and hive_ce_flutter to your project. The API is identical — it’s a drop-in replacement.
✅ Use Hive when:
  • You need to store custom Dart objects (notes, tasks, user profiles)
  • You’re building a notes app, shopping cart, or chat message cache
  • You want fast reads without writing SQL
  • You need Web platform support
  • You want built-in AES-256 encryption
  • Your data doesn’t have complex relationships between entities

Setup

Primitive Storage (No TypeAdapter Needed)

Storing Custom Objects with TypeAdapter

To store custom Dart classes, annotate the class and run code generation. The generator creates a TypeAdapter that Hive uses to serialise/deserialise your object:

Encrypted Box (AES-256)

5. sqflite: Structured Relational Data

sqflite is a Flutter plugin wrapping SQLite — the industry-standard embedded relational database that’s been around for over 20 years. It supports full SQL: CREATE TABLE, INSERT, SELECT, WHERE, JOIN, transactions, and schema migrations. Use it when your data has structure and relationships.

✅ Use sqflite when:
  • Your data has relationships (users → orders, students → attendance records)
  • You need complex filtering, sorting, or JOINs
  • Your dataset could grow to thousands of rows
  • You or your team already knows SQL
  • You need transactions (e.g. transfer money between accounts atomically)
  • You’re building an inventory, finance, or record-keeping app

Setup

The DatabaseHelper Singleton (Critical Pattern)

sqflite requires careful initialisation. The standard pattern uses a singleton helper class with a static Database? instance so the database file is only opened once, not on every query. Getting this wrong causes performance issues and occasional corruption:

Model Class with toMap / fromMap

Full CRUD Operations

JOIN Example: Relational Data

6. Honorable Mentions

Before picking one of the three main options, here are four additional packages that come up frequently and are worth knowing about:

Package What it is Use when
flutter_secure_storageEncrypted key-value storage (Keychain on iOS, Keystore on Android)Storing auth tokens, passwords, API keys — anything sensitive
Drift (formerly Moor)Type-safe ORM layer on top of SQLite with reactive streamsYou want sqflite’s power without raw SQL strings — type errors caught at compile time
hive_ceCommunity Edition fork of Hive — actively maintainedEvery new project that would have used Hive — use this instead of the original
ObjectBox / IsarHigh-performance NoSQL databasesProceed with caution — ObjectBox is not open source, Isar is also community-abandoned in 2025
💡 When you don’t need any of these
Sometimes no local database is needed at all. If your data is purely session-scoped (doesn’t need to survive an app restart), just use a Dart List in state with setState or a ChangeNotifier. Don’t add a database dependency if the problem doesn’t require one.

7. Common Mistakes

Mistake 1: Storing sensitive data in SharedPreferences

Mistake 2: Storing JSON-encoded objects in SharedPreferences

Mistake 3: Opening the sqflite database on every query

Mistake 4: Using the original hive package in 2026

Mistake 5: Forgetting Hive.initFlutter() before runApp

Mistake 6: Using sqflite for simple user preferences

8. Interview Q&A

Q: What is the difference between SharedPreferences, Hive, and sqflite in Flutter?

A: SharedPreferences stores only primitive key-value pairs (int, bool, String, double, List<String>) — perfect for app settings and flags, but can’t store objects. Hive stores any Dart object in a fast binary format using TypeAdapters, making it ideal for offline lists and object caching without SQL. sqflite wraps SQLite and provides full relational database capabilities with SQL queries, JOINs, and transactions — required when your data has relationships or needs complex filtering.
Q: Which Flutter local storage should I use for a notes app?

A: Hive (using hive_ce) is the right choice for a notes app. Notes are self-contained objects with no relationships between them. Hive handles custom Dart objects natively via TypeAdapters, is faster than sqflite for simple reads and writes, and requires no SQL knowledge. sqflite would be overkill unless you need to JOIN notes to categories or users, or need full-text search across thousands of records.
Q: Is it safe to store passwords or tokens in SharedPreferences?

A: No. SharedPreferences stores data in plaintext on disk with no encryption. Sensitive values like auth tokens, passwords, and API keys must be stored using flutter_secure_storage, which uses iOS Keychain and Android Keystore — the platform’s encrypted credential stores.
Q: What is a TypeAdapter in Hive?

A: A TypeAdapter is a class that tells Hive how to serialise and deserialise a custom Dart object to and from binary storage. You annotate your class with @HiveType and its fields with @HiveField, then run build_runner to auto-generate the adapter. Without a TypeAdapter, Hive can only store primitive values — with one registered, it can store any Dart object directly in a Box.
Q: Why do you need a singleton DatabaseHelper for sqflite?

A: SQLite database files can only be safely accessed by one open connection at a time within a Dart isolate. If you call openDatabase() on every query, you re-open the file repeatedly — causing overhead and risking file lock errors. The singleton pattern ensures the file is opened exactly once and the same Database instance is reused for every subsequent operation.
Post Why it’s relevant
Notes App Part 2: Local Persistence with SharedPreferencesSee SharedPreferences in action in a real project — the Notes app uses it for note persistence.
Flutter Dark Mode ToggleThe dark mode post uses SharedPreferences to persist the theme choice — a textbook use case for this guide.
Understanding pubspec.yamlAdding shared_preferences, hive_ce, or sqflite all start with editing pubspec.yaml correctly.
Dart Crash Course (Part 0)All three storage options use async/await — the Dart crash course covers exactly the language features needed here.
Flutter Widgets: Stateless vs StatefulLoading stored data in initState is the standard pattern — requires understanding StatefulWidget’s lifecycle.
Show 1 Comment

1 Comment

Leave a Reply