Migration to Flutter Guide
Discover our battle-tested 21-step framework for a smooth and successful migration to Flutter!
Jump to:

Local storage in Flutter

What is local storage in Flutter?

Local storage in Flutter app development means persisting data directly on the user’s device so it survives app restarts and can be accessed offline. It is commonly used for user preferences, cached API data, authentication state, and downloaded files.

Flutter does not have a single built-in storage system. Instead, different tools are used depending on the type, size, and sensitivity of the data.

Why does it matter in Flutter app development?

Without local storage:

  • User settings are lost after restart.
  • Offline usage is impossible.
  • Apps feel slower due to repeated network calls.

Using the wrong storage type can also cause crashes, security issues, or performance problems.

How does it work?

Flutter communicates with native Android and iOS storage through plugins. These plugins expose asynchronous Dart APIs, while the actual data is stored in system storage such as SharedPreferences, databases, or the file system.

Example of simple key–value storage:

final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isDarkMode', true);

Common local storage options

Each solution has a specific role:

  • SharedPreferences: Simple key–value storage for small, non-sensitive data like flags or UI settings.
  • Isar / Hive / SQLite: Databases for structured or larger datasets. Isar is the modern successor to Hive, offering better performance and queries. SQLite is ideal for relational data.
  • flutter_secure_storage: Encrypted storage backed by Keychain (iOS) or Keystore (Android). Best for tokens and credentials.
  • File storage (path_provider): Used for images, PDFs, or other binary files. Databases should store file paths, not file contents.

How to use local storage in Flutter correctly

A common production setup looks like this:

  • SharedPreferences → app settings
  • flutter_secure_storage → auth tokens
  • Isar / SQLite → app data
  • File system → media and documents

All storage access is asynchronous and should live outside UI widgets.

Best practices for using local storage

When working with local storage:

  • Access storage through repositories or services
  • Always use async/await
  • Handle errors explicitly
  • Keep UI independent from storage logic

Common mistakes to avoid

Several issues appear frequently in Flutter apps:

  • Storing sensitive data in SharedPreferences: This data is not encrypted.
  • Using SharedPreferences as a database: It is not designed for large or complex data.
  • Ignoring errors in flutter_secure_storage: On Android, app reinstall can leave old encryption keys, causing read crashes. Always wrap reads in try-catch and clear storage if needed.
  • Saving images as Base64 in databases: This wastes memory and hurts performance. Use files instead.

When to use local storage?

Use local storage in Flutter when:

  • Persistence across app launches: Storing user preferences, session tokens, or cached data so it survives app restarts.
  • Offline access is required: Apps that need to function without an internet connection, like note-taking apps, e-readers, or offline-first e-commerce.
  • Reducing network usage: Caching API responses, images, or configuration data to avoid repeated downloads. Local storage often goes hand-in-hand with cache invalidation, meaning cached data should have a TTL (time-to-live) or expiration to prevent users from seeing outdated information.
  • Improving performance: Quick local reads can reduce delays compared to fetching from a remote server every time.
  • Structured or semi-structured data management: Depending on the storage choice, you can store relational data (SQLite/Drift), key-value pairs (SharedPreferences/Hive), or serialized objects (Hive, Isar).

Choosing the right storage solution also depends on scale: small, lightweight preferences can use SharedPreferences, while complex, relational data benefits from SQLite or Drift, and high-performance object storage can use Hive or Isar.

When not to use local storage?

Avoid relying on local storage when:

  • Data must always be real-time: Stock prices, chat messages, or collaborative content require live updates from a server.
  • Sensitive data is unencrypted: Storing passwords, tokens, or personal data in plain local storage can expose security risks; use secure storage plugins instead.
  • Temporary UI state is sufficient: Transient information like form input, scroll positions, or in-progress animations doesn’t need persistence.
  • Cross-device synchronization is required: Local storage doesn’t automatically sync between devices; remote databases or cloud storage are more suitable.

Local storage in Flutter is flexible and powerful, but making the right choice – considering security, data structure, cache policies, and access patterns – is essential for maintainable and reliable apps.

Learn more

Why Firestore, Part I: Reasons to Love It

Why Firestore, Part I: Reasons to Love It

Firestore and Firebase suite are great technologies. They allow developers to build some features in Flutter and other mobile frameworks really fast. However, Firestore has also many pain points that outweigh the pros in most of the more advanced cases. Is Firestore appropriate for you? Read on to find out why!

Firestore limiations

Why Firestore, Part II: Reasons to Hate It

Firestore (and Firebase) is a really great solution for many different use cases. However, there is a number of limitations that make using Firestore painful. Tricky latency, data migration problems, and complicated privacy are just the beginning of the trouble. Read the article to find out why!