image

23 Dec 2025

9K

35K

Flutter & Shared Preferences: Storing User Settings

In modern applications, personalizing the user experience is paramount. Users often expect their preferences, such as theme settings, notification choices, or last-used configurations, to persist across app sessions. For Flutter developers, shared_preferences is a popular and straightforward solution for storing such lightweight user settings.

Understanding Shared Preferences

shared_preferences is a Flutter plugin that wraps platform-specific persistent storage mechanisms. On Android, it uses SharedPreferences, and on iOS, it uses NSUserDefaults. It provides a simple API for reading and writing primitive data types (booleans, integers, doubles, strings, and lists of strings) using a key-value pair system. It's ideal for non-sensitive data and user preferences, but not suitable for large or complex datasets, or for sensitive information like passwords.

Getting Started: Adding the Dependency

To use shared_preferences in your Flutter project, you first need to add it as a dependency in your pubspec.yaml file:


dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^2.2.0 # Use the latest version available

After adding the dependency, run flutter pub get to fetch the package.

Basic Usage: Saving and Retrieving Data

The core of shared_preferences involves asynchronously getting an instance of SharedPreferences and then using its setter and getter methods.

1. Saving Data

To save a value, you first need to get an instance of SharedPreferences and then call the appropriate setter method based on the data type (e.g., setBool, setInt, setString, setDouble, setStringList).


import 'package:shared_preferences/shared_preferences.dart';

Future saveUserSettings({
  required bool isDarkMode,
  required int fontSize,
  required String username,
}) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();

  await prefs.setBool('isDarkMode', isDarkMode);
  await prefs.setInt('fontSize', fontSize);
  await prefs.setString('username', username);

  print('User settings saved successfully!');
}

2. Retrieving Data

Retrieving data is equally straightforward, using the corresponding getter methods (e.g., getBool, getInt, getString). These methods return null if the key does not exist, so it's good practice to provide a default fallback value using the ?? operator.


import 'package:shared_preferences/shared_preferences.dart';

Future loadUserSettings() async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();

  final bool? isDarkMode = prefs.getBool('isDarkMode');
  final int? fontSize = prefs.getInt('fontSize');
  final String? username = prefs.getString('username');

  print('Loaded Settings:');
  print('Dark Mode: ${isDarkMode ?? false}'); // Default to false
  print('Font Size: ${fontSize ?? 14}');     // Default to 14
  print('Username: ${username ?? 'Guest'}'); // Default to 'Guest'
}

3. Removing Data

If you need to remove a specific key-value pair, use the remove() method:


import 'package:shared_preferences/shared_preferences.dart';

Future removeSetting(String key) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.remove(key);
  print('Setting "$key" removed.');
}

4. Clearing All Data

To clear all stored preferences for your application, use the clear() method:


import 'package:shared_preferences/shared_preferences.dart';

Future clearAllSettings() async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.clear();
  print('All settings cleared.');
}

Example: Implementing a Theme Switcher

Let's integrate this into a simple Flutter UI to persist a user's dark mode preference.


import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State createState() => _MyAppState();
}

class _MyAppState extends State {
  bool _isDarkMode = false;

  @override
  void initState() {
    super.initState();
    _loadThemeSetting();
  }

  Future _loadThemeSetting() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _isDarkMode = prefs.getBool('isDarkMode') ?? false;
    });
  }

  Future _toggleTheme(bool value) async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _isDarkMode = value;
    });
    await prefs.setBool('isDarkMode', value);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter User Settings',
      theme: _isDarkMode ? ThemeData.dark() : ThemeData.light(),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('User Settings'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Dark Mode',
                style: Theme.of(context).textTheme.headlineSmall,
              ),
              Switch(
                value: _isDarkMode,
                onChanged: _toggleTheme,
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // Example of saving other settings
                  saveUserSettings(
                    isDarkMode: _isDarkMode,
                    fontSize: 18,
                    username: 'FlutterDev',
                  );
                },
                child: const Text('Save Other Settings (Demo)'),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: loadUserSettings,
                child: const Text('Load Other Settings (Demo)'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// Re-using the functions defined earlier for demonstration
Future saveUserSettings({
  required bool isDarkMode,
  required int fontSize,
  required String username,
}) async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setBool('isDarkMode', isDarkMode); // This is also handled by _toggleTheme
  await prefs.setInt('fontSize', fontSize);
  await prefs.setString('username', username);
  print('Demo: Other user settings saved successfully!');
}

Future loadUserSettings() async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  final bool? isDarkMode = prefs.getBool('isDarkMode');
  final int? fontSize = prefs.getInt('fontSize');
  final String? username = prefs.getString('username');

  print('Demo: Loaded Other Settings:');
  print('Dark Mode: ${isDarkMode ?? false}');
  print('Font Size: ${fontSize ?? 14}');
  print('Username: ${username ?? 'Guest'}');
}

Best Practices and Considerations

  • Asynchronous Operations: All `shared_preferences` operations are asynchronous and return `Future`s. Always `await` them to ensure data is written or read correctly before proceeding.
  • Data Types: Only primitive types (bool, int, double, String) and `List` are directly supported. For complex objects, you'll need to serialize them to JSON strings before saving and deserialize them upon retrieval.
  • Not for Sensitive Data: `shared_preferences` stores data in plain text on the device. It is not encrypted and can be accessed by a rooted/jailbroken device. For sensitive information, consider using plugins like `flutter_secure_storage`.
  • Performance: While efficient for small amounts of data, `shared_preferences` is not optimized for large-scale data storage or frequent, high-volume operations. For databases, consider SQLite (e.g., `sqflite`) or NoSQL solutions.
  • Error Handling: While `shared_preferences` is generally robust, it's good practice to wrap critical operations in `try-catch` blocks, especially when dealing with external dependencies or user input.

Conclusion

shared_preferences provides a simple, efficient, and widely adopted solution for persisting lightweight user settings and preferences in Flutter applications. By understanding its capabilities and limitations, developers can significantly enhance the user experience by making their apps more personalized and convenient.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is