When to use Shared Preferences
In many mobile, web, and desktop applications a tiny amount of data needs to survive app restarts – things like a user’s theme choice, a flag indicating whether the onboarding flow has been completed, or a token that determines if a feature should be enabled. The **shared_preferences** package gives Flutter developers a straightforward, asynchronous API to store and retrieve such primitive values without having to write platform‑specific code. By abstracting the native preferences mechanisms on Android (SharedPreferences), iOS (NSUserDefaults), Web (localStorage), and desktop (file‑based storage), it lets you focus on the business logic while keeping the persistence layer lightweight.
Under the hood the plugin serialises supported types – booleans, integers, doubles, strings, and string‑list collections – into the platform’s native storage format. All operations return a `Future`, ensuring that reads and writes are performed off the UI thread and that your UI remains responsive. The package is part of the official Flutter ecosystem, which means it receives regular updates, follows the same versioning cadence as Flutter itself, and integrates seamlessly with the tooling you already use.
When deciding whether to reach for **shared_preferences**, consider the size and nature of the data. It shines for configuration settings, feature toggles, and small caches that are read frequently but rarely modified. In a clean architecture, you would typically wrap the plugin in a repository or data‑source class, exposing a domain‑level interface that can be swapped out for mocks during testing. This approach keeps your UI layer agnostic of the underlying storage mechanism and makes it easy to adopt more sophisticated solutions later if your data needs grow.
Getting started is intentionally minimal. Run `flutter pub add shared_preferences` to add the dependency, then import the package and obtain an instance of `SharedPreferences` via `await SharedPreferences.getInstance()`. From there you can call methods such as `setBool`, `setString`, `getInt`, or `remove`. The following snippet demonstrates a typical pattern for persisting a dark‑mode preference and reading it back on app launch.
While **shared_preferences** is reliable for small payloads, it is not a substitute for a full‑featured database. Storing large JSON blobs or binary data can quickly exceed platform limits and degrade performance. Because the data is stored in plain text on the device, you should avoid persisting sensitive information unless you add an extra encryption layer. Additionally, be aware that the API may change when new primitive types are added, so version your access code and include migration logic if you ever need to evolve the stored schema.
In summary, **shared_preferences** offers a fast, zero‑configuration way to keep user‑specific settings and lightweight flags available across app sessions. Its cross‑platform reach, simple API, and official support make it a go‑to choice for most Flutter projects that need persistent, non‑relational data. By encapsulating it behind an abstraction layer, you retain flexibility while enjoying the convenience of a proven, community‑trusted solution.
Pros
- easy to use API
- cross‑platform support
- no native code required for most platforms
- asynchronous operations keep UI smooth
Watch outs
- limited to primitive types
- not suitable for large or relational data
- data stored in plain text (no built‑in encryption)
- potential platform‑specific size limits
Setup notes
Add the dependency with the command: ``` flutter pub add shared_preferences ``` Then run `flutter pub get` and import the package: ```dart import 'package:shared_preferences/shared_preferences.dart'; ```
Supports Android, iOS, Web, macOS, Windows, and Linux. Requires Flutter 2.0 or newer. On web, data is stored in `window.localStorage`; on desktop, a file is created in the application support directory.
```dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ThemeToggle extends StatefulWidget {
const ThemeToggle({Key? key}) : super(key: key);
@override
State<ThemeToggle> createState() => _ThemeToggleState();
}
class _ThemeToggleState extends State<ThemeToggle> {
bool _isDark = false;
@override
void initState() {
super.initState();
_loadPreference();
}
Future<void> _loadPreference() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_isDark = prefs.getBool('darkMode') ?? false;
});
}
Future<void> _toggleTheme(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('darkMode', value);
setState(() => _isDark = value);
}
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: const Text('Dark Mode'),
value: _isDark,
onChanged: _toggleTheme,
);
}
}
```