Flutter Lesson 50 of 83 3 min read
shared_preferences in Flutter: Saving Simple Data
Save small values in Flutter with shared_preferences: settings, flags and tokens, plus secure storage for sensitive data.
On this page
shared_preferences stores small pieces of data as key and value pairs that survive restarts. It suits settings and flags: the chosen theme, whether the user has seen the welcome screen, the last selected tab.
flutter pub add shared_preferences
Reading and writing #
import 'package:shared_preferences/shared_preferences.dart';
Future<void> example() async {
final prefs = await SharedPreferences.getInstance();
// Write
await prefs.setInt('launchCount', 5);
await prefs.setBool('darkMode', true);
await prefs.setString('userName', 'Asha');
await prefs.setDouble('fontScale', 1.2);
await prefs.setStringList('recentSearches', ['shoes', 'bag']);
// Read: null if the key was never set, so give a default
final count = prefs.getInt('launchCount') ?? 0;
final dark = prefs.getBool('darkMode') ?? false;
final name = prefs.getString('userName');
// Remove
await prefs.remove('userName');
await prefs.clear(); // everything
}
Five types are supported: int, double, bool, String and List<String>.
A counter that remembers #
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(const MaterialApp(home: CounterPage()));
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
static const _key = 'counter';
int _count = 0;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
final prefs = await SharedPreferences.getInstance();
if (!mounted) return;
setState(() => _count = prefs.getInt(_key) ?? 0);
}
Future<void> _increment() async {
setState(() => _count++);
final prefs = await SharedPreferences.getInstance();
await prefs.setInt(_key, _count);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Saved counter')),
body: Center(child: Text('$_count', style: const TextStyle(fontSize: 48))),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child: const Icon(Icons.add),
),
);
}
}
Close the app completely and open it again. The number is still there.
Wrap it in a class #
Key strings scattered through the app invite typos. Keep them in one place.
class SettingsStore {
SettingsStore(this._prefs);
final SharedPreferences _prefs;
static const _themeKey = 'themeMode';
static const _onboardedKey = 'onboarded';
ThemeMode get themeMode =>
ThemeMode.values.byName(_prefs.getString(_themeKey) ?? 'system');
Future<void> setThemeMode(ThemeMode mode) => _prefs.setString(_themeKey, mode.name);
bool get hasOnboarded => _prefs.getBool(_onboardedKey) ?? false;
Future<void> completeOnboarding() => _prefs.setBool(_onboardedKey, true);
}
Load the preferences before the app starts, so the first frame already has the right theme.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); // required before using plugins in main
final prefs = await SharedPreferences.getInstance();
runApp(MyApp(settings: SettingsStore(prefs)));
}
Storing an object #
Encode it as JSON text.
import 'dart:convert';
Future<void> saveUser(SharedPreferences prefs, User user) =>
prefs.setString('user', jsonEncode(user.toJson()));
User? loadUser(SharedPreferences prefs) {
final text = prefs.getString('user');
if (text == null) return null;
return User.fromJson(jsonDecode(text) as Map<String, dynamic>);
}
This is fine for one small object. For lists of records, use a database.
The newer API #
The package also provides SharedPreferencesAsync and SharedPreferencesWithCache, which the maintainers recommend for new code. The method names are the same idea (setInt, getInt), with reads that return futures in the async version. Everything in this lesson carries over.
What not to store here #
| Data | Use instead |
|---|---|
| Passwords, tokens, API keys | flutter_secure_storage |
| Lists of records you search or sort | SQLite or another database |
| Images and large files | Files, with the path stored in a database |
| Data that must sync between devices | A backend such as Firebase |
Preferences are stored as plain text on the device. They are not encrypted.
Secure storage #
flutter_secure_storage keeps values in the iOS Keychain and the Android Keystore.
flutter pub add flutter_secure_storage
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
const storage = FlutterSecureStorage();
await storage.write(key: 'authToken', value: token);
final token = await storage.read(key: 'authToken'); // null if absent
await storage.delete(key: 'authToken');
Use it for anything that would cause harm if read from a lost or compromised phone.
Try it yourself #
Add a settings screen with a dark mode switch, a font size slider and a “user name” field. Save each with shared_preferences, and load them before runApp so the app opens with the saved values.