Flutter Local Storage SharedPrefs

Not all data needs a server. User preferences, login tokens, dark mode settings, and onboarding completion flags belong on the device. Flutter provides two common ways to store data locally: SharedPreferences for simple key-value data, and SQLite for structured data.

Types of Local Storage

  ┌──────────────────────────────────────────────────┐
  │           LOCAL STORAGE OPTIONS                  │
  ├─────────────────────┬────────────────────────────┤
  │ SharedPreferences   │ Simple key → value pairs   │
  │                     │ Best for: settings, tokens │
  ├─────────────────────┼────────────────────────────┤
  │ SQLite (sqflite)    │ Full relational database   │
  │                     │ Best for: lists, records   │
  ├─────────────────────┼────────────────────────────┤
  │ Hive                │ Fast NoSQL database        │
  │                     │ Best for: objects, offline │
  └─────────────────────┴────────────────────────────┘

SharedPreferences — Simple Key-Value Storage

SharedPreferences stores small pieces of data as key-value pairs, similar to a settings file on the device.

Step 1 — Add the Package

  In pubspec.yaml:
  ─────────────────
  dependencies:
    shared_preferences: ^2.2.3

  Run: flutter pub get

Step 2 — Save Data

import 'package:shared_preferences/shared_preferences.dart';

Future<void> saveUserData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();

  await prefs.setString('username', 'Ravi');
  await prefs.setInt('age', 28);
  await prefs.setBool('darkMode', true);
  await prefs.setDouble('rating', 4.5);

  print('Data saved!');
}

Step 3 — Read Data

Future<void> readUserData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();

  String? username = prefs.getString('username');   // 'Ravi'
  int? age = prefs.getInt('age');                   // 28
  bool? darkMode = prefs.getBool('darkMode');       // true

  print('Username: $username, Age: $age, Dark: $darkMode');
}

Step 4 — Delete Data

Future<void> clearData() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.remove('username');       // Remove one key
  await prefs.clear();                  // Remove all keys
}

Real-World Example — Remember Login State

Many apps skip the login screen if the user is already signed in. SharedPreferences stores the login state between sessions.

class AuthService {
  static const String _loginKey = 'isLoggedIn';
  static const String _tokenKey = 'authToken';

  // Save login state after successful login
  Future<void> saveLoginState(String token) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_loginKey, true);
    await prefs.setString(_tokenKey, token);
  }

  // Check login state on app start
  Future<bool> isLoggedIn() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getBool(_loginKey) ?? false;
  }

  // Clear on logout
  Future<void> logout() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.clear();
  }
}
  App Launch Flow:
  ─────────────────────────────────────────────
  App Starts
       ↓
  Check isLoggedIn()
       ↓
  ┌───────────────────────────────────────┐
  │ true  → go to HomeScreen              │
  │ false → go to LoginScreen             │
  └───────────────────────────────────────┘

Dark Mode Preference — Live Example

class ThemeSettings extends StatefulWidget {
  @override
  State<ThemeSettings> createState() => _ThemeSettingsState();
}

class _ThemeSettingsState extends State<ThemeSettings> {
  bool _isDark = false;

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

  Future<void> _loadTheme() 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 ListTile(
      title: Text('Dark Mode'),
      trailing: Switch(
        value: _isDark,
        onChanged: _toggleTheme,
      ),
    );
  }
}

SQLite with sqflite — For Structured Data

When you need to store a list of records (tasks, contacts, products), use sqflite. It gives you a full SQL database on the device.

Add the Package

  dependencies:
    sqflite: ^2.3.3
    path: ^1.9.0

Create and Use a Database

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static Database? _db;

  Future<Database> get database async {
    if (_db != null) return _db!;
    _db = await _initDB();
    return _db!;
  }

  Future<Database> _initDB() async {
    String path = join(await getDatabasesPath(), 'tasks.db');
    return openDatabase(
      path,
      version: 1,
      onCreate: (db, version) async {
        await db.execute('''
          CREATE TABLE tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT,
            isDone INTEGER
          )
        ''');
      },
    );
  }

  Future<void> insertTask(String title) async {
    final db = await database;
    await db.insert('tasks', {'title': title, 'isDone': 0});
  }

  Future<List<Map<String, dynamic>>> getTasks() async {
    final db = await database;
    return db.query('tasks');
  }

  Future<void> deleteTask(int id) async {
    final db = await database;
    await db.delete('tasks', where: 'id = ?', whereArgs: [id]);
  }
}

Choosing the Right Storage

Data TypeBest Storage Option
Settings, flags, tokensSharedPreferences
Lists of structured recordssqflite (SQLite)
Dart objects, fast accessHive
Large files (images, PDFs)path_provider + File

Leave a Comment

Your email address will not be published. Required fields are marked *