
You: “I just need to store a flag that says if the user has seen onboarding.”
Also you: accidentally creates a multi-isolate caching nightmare that gaslights you into thinking a user is logged in when they’re not.
Let’s fix that.
🤷♂️ What Even Are Shared Preferences?
Alright, imagine you’re building a Flutter app.
You want to remember things like:
- whether a user tapped “Dark Mode”
- if onboarding was skipped
- or how many times someone opened your app and immediately closed it (rude, but ok)
You don’t want to deal with databases, auth flows, or files.
You just want something like:
prefs.setBool('userSawIntro', true);Boom. ✅
That's SharedPreferences — Flutter's way of saying,
“Here, have a little key-value vault that sticks around even after the app restarts.”
It’s like Post-it notes... but for your app.
🚗 The Beginner Ride: How We All Started
Remember this?
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isLoggedIn', true);You probably slapped this somewhere in your onboarding logic and called it a day.
And honestly, for small apps, that’s fine. But as your app grows, things get weird.
Because guess what?
The original SharedPreferences API is a liar.
🤥 How It Lies (Yes, Really)
It uses a cache.
That means when you read a value like prefs.getBool('isLoggedIn'),
it’s pulling it from memory — not the actual disk.
So if something else changes the data in the background (like Firebase Messaging, another isolate, or native code), your app might say:
“Yup, user is logged in!”
...when they’re very much not. 🙃
🧬 The Evolution: shared_preferences: ^2.5.3
Flutter team saw the mess and said,
"Let’s make it better without breaking everything."
Now we have 3 different APIs to choose from depending on your chaos level:
1. SharedPreferences (a.k.a. The OG)
- Fast reads
- Uses cache
- Works... until it doesn’t
Use this if your app is small, single-threaded, and you’re okay living a little dangerously.
2. SharedPreferencesAsync
- Fully async
- NO cache
- Always fresh data
- Slightly slower, but 100% accurate
Perfect for you if:
- You’ve got background isolates
- You’re mixing native code
- You want the truth and nothing but the truth
final prefs = SharedPreferencesAsync();
await prefs.setString('mode', 'dark');
final mode = await prefs.getString('mode');3. SharedPreferencesWithCache
- Async setup, but fast sync reads after that
- You can pick which keys to cache
- Honestly, a pretty chill middle ground
final prefs = await SharedPreferencesWithCache.create(
cacheOptions: SharedPreferencesWithCacheOptions(
allowList: {'mode', 'isLoggedIn'},
),
);
prefs.setBool('isLoggedIn', true);Think of it as:
AsyncPrefs got tired of being slow and got therapy. Now it’s balanced.
🧙 Android Wizards: DataStore vs SharedPreferences
On Android, Flutter now prefers Jetpack DataStore over old-school SharedPreferences.
BUT — if you’re working with legacy code or need compatibility, you can still go full old-school:
SharedPreferencesAsyncAndroidOptions(
backend: SharedPreferencesAndroidBackendLibrary.SharedPreferences,
originalSharedPreferencesOptions: AndroidSharedPreferencesStoreOptions(
fileName: 'legacy_baggage',
),
);🧼 Migrating to the New Stuff (Without Wiping Memory)
Yes, you can migrate to Async or WithCache without nuking your user's data:
await migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary(
legacySharedPreferencesInstance: oldPrefs,
sharedPreferencesAsyncOptions: newOptions,
migrationCompletedKey: 'migrationDone',
);Run it on every launch. It’s like flossing for your storage logic.
🧨 Pro Tips You Shouldn’t Ignore
- Don’t store sensitive data (passwords, tokens, grandma’s bank pin). It’s not encrypted.
- If you must clear all data, use:
- await prefs.clear();
- If your reads feel weird, try:
- await prefs.reload();
- Want to share prefs with a native Android/iOS app?
Use .setPrefix('') to remove Flutter’s default flutter. prefix — but brace for chaos.
🧳 Platform Compatibility (aka: "Will This Work on...")
PlatformBackendAndroidDataStore or SharedPreferencesiOS/macOSNSUserDefaultsWebLocalStorageWindowsAppData/RoamingLinuxXDG_DATA_HOME
Basically: yes, it works almost everywhere.
📦 Just Gimme the Package
Here’s what you need in pubspec.yaml:
shared_preferences: ^2.5.3Then run flutter pub get like the majestic developer you are.
🧠 TL;DR — Which One Should You Use?
- Simple app, single isolate: SharedPreferences
- Background services, multiple isolates: SharedPreferencesAsync
- You want speed + accuracy: SharedPreferencesWithCache
🎬 Final Thoughts
Shared Preferences aren’t just a beginner tool anymore.
With Flutter 3 and Dart 3 compatibility, shared_preferences: ^2.5.3 is now flexible, safer, and way more powerful than before.
So go forth, store responsibly, and stop yelling at your cache for being out of date.
Your future self (and your bug tracker) will thank you.