Flutter Local Data Storage (SharedPreferences)
Local storage allows us to save a small amount of data on a user’s device without requiring an internet connection. Learn how to store data in local storage in Flutter with example.

Flutter is a powerful framework used for building cross-platform applications. Sometimes it is often needed to store data locally in Flutter like any modern application. This data can be user preferences, app settings, session token or any offline data. In this post we will store data in local storage using Flutter shared preferences package.
Why Store Data Locally in Flutter?
Applications often store data locally for various purposes. Following are some common reasons to save data to local storage in Flutter.
- When saving user settings.
- When offline access to data is needed.
- When network responses need to be stored.
- When storing small amount of data.
How to Store Data in Flutter Local Storage?
In Flutter, local storage is commonly implemented using the SharedPreferences package to save data in local storage, which stores data as key-value pairs on the device. In this post we will use shared preferences package to store a list of favorite books. The following is the breakdown of flow:
- Install Flutter shared preferences package.
- Create a Flutter model for book object.
- Create a provider to maintain favorite books list.
- Use a consumer to display books from favorite list.
Step 1: Add and Install Flutter Shared Preference Package
First thing we need is a package to handle local data storage in flutter. We will use Shared Preference package of Flutter. Run the following two commands to add and install the package:
flutter pub add shared_preferences
flutter pub get
Step 2: Create a Flutter Book Model Class
Next we need to create a Flutter model for our book object to maintain list in local storage. We will use basic model as in code snippet below:
// models/book.dart
class Book {
// Fields
final int id;
final String title;
final String author;
// Constructor
Book({
required this.id,
required this.title,
required this.author
});
// Factory method to create a Book object from JSON
factory Book.fromJson(Map<String, dynamic> json) {
return Book(
id: json['id'],
title: json['title'],
author: json['author'],
);
}
// Method to convert Book object to JSON
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'author': author,
};
}
// Function to parse a list of Books from JSON
static List<Book> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((json) => Book.fromJson(json)).toList();
}
}
Step 3: Create a Provider to Store Data in Local Storage
Next we create a Flutter provider for our books to be managed in local storage. The provider will use ChangeNotifier for interactive UI updates. So wherever this provider will be used via a consumer it will be updated the moment a book is added or removed from list.
- Create a class
BookProviderwithChangeNotifierin providers directory. - Add the local list variable
_favoriteBookswhich is initially an empty array. - Add a getter
favoriteBooksvariable and return the favorite books from list. - Add a
loadBooks()method to load existing books in storage. - Add a
addBook()method to add a new book to storage list. - Add a
removeBook()method to remove existing book from storage list. - Add a
isFavoriteBook()method to check byidif a book exists in storage list.
// providers/book_provider.dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/book.dart';
class BookProvider with ChangeNotifier {
List<Book> _favoriteBooks = [];
List<Book> get favoriteBooks => _favoriteBooks;
BookProvider() {
loadBooks();
}
Future<void> loadBooks() async {
final prefs = await SharedPreferences.getInstance();
final favoriteBooks = prefs.getStringList('favorite_books') ?? [];
_favoriteBooks = favoriteBooks
.map((bookJson) => Book.fromJson(json.decode(bookJson)))
.toList();
notifyListeners();
}
Future<void> addBook(Book book) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final favoriteBooks = prefs.getStringList('favorite_books') ?? [];
if (!isFavoriteBook(book.id)) {
favoriteBooks.insert(favoriteBooks.length, json.encode(book.toJson()));
}
await prefs.setStringList('favorite_books', favoriteBooks);
_favoriteBooks = favoriteBooks
.map((bookJson) => Book.fromJson(json.decode(bookJson)))
.toList();
notifyListeners();
}
Future<void> removeBook(Book book) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final favoriteBooks = prefs.getStringList('favorite_books') ?? [];
if (isFavoriteBook(book.id)) {
favoriteBooks.removeWhere((item) => item == json.encode(book.toJson()));
}
await prefs.setStringList('favorite_books', favoriteBooks);
_favoriteBooks = favoriteBooks
.map((bookJson) => Book.fromJson(json.decode(bookJson)))
.toList();
notifyListeners();
}
bool isFavoriteBook(int bookId) {
return _favoriteBooks.any((item) {
return item.id == bookId;
});
}
}
Step 4: Use a Consumer to Display Data From Local Storage
Now that we have our Flutter model and provider ready, it is time to display items from local storage in our Flutter application. We have used two text fields as an example but these lists can come form actual data like API response. The following code snippet is able to do the following:
- Show favorite books from local storage.
- Add a new book to local storage.
- Remove a book from local storage.
// screens/home_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/book_provider.dart';
import '../models/book.dart';
import 'dart:math';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
final titleController = TextEditingController();
final authorController = TextEditingController();
return Scaffold(
appBar: AppBar(title: const Text('Book List')),
body: Consumer<BookProvider>(
builder: (context, bookProvider, _) {
final favoriteBooks = bookProvider.favoriteBooks;
return Column(
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: [
TextField(
controller: titleController,
decoration: const InputDecoration(labelText: 'Title'),
),
TextField(
controller: authorController,
decoration: const InputDecoration(labelText: 'Author'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
final id = Random().nextInt(10000);
final newBook = Book(
id: id,
title: titleController.text,
author: authorController.text,
);
context.read<BookProvider>().addBook(newBook);
titleController.clear();
authorController.clear();
},
child: const Text('Add Book'),
),
],
),
),
const Divider(),
Expanded(
child: ListView.builder(
itemCount: favoriteBooks.length,
itemBuilder: (ctx, index) {
final book = favoriteBooks[index];
return ListTile(
title: Text(book.title),
subtitle: Text('By ${book.author}'),
trailing: IconButton(
onPressed: () async {
context
.read<BookProvider>()
.removeBook(book);
},
icon: Icon(
Icons.delete,
)));
},
),
),
],
);
},
),
);
}
}
We demonstrated how to add items list to local storage in Flutter with code examples. The code snippets in this post provides a basic idea of how to utilize local storage in Flutter. It is important to use consumer when showing the list from local storage to ensure an interactive UI interface.