How to Save Objects in SharedPreferences in Flutter

- 👤 Andrés Cruz

🇪🇸 En español

In developing Flutter applications, it's often necessary to store values persistently within the application; for this, we have many options. The most complete would be to use an SQLite database, but, if we only want to store a few pieces of data, such as the user and related data like a shopping cart, purchased courses, etc., we can opt for a simpler approach such as User Preferences, which is a package available for Android, iOS, Windows, MacOS, and any technology you want to use.

We start from the point where we already have data to persist because we learned to send and receive data from the Internet using an application in Flutter.

⭐ What is SharedPreferences and what is it used for in Flutter

SharedPreferences is a persistent local storage system, designed to save simple data in the form of key-value pairs, such as strings, numbers, booleans, or lists.

Unlike in-memory variables, these values are saved to disk, so they remain available even if the user closes the app.

SharedPreferences is a persistent storage mechanism that allows Flutter applications (on both Android and iOS) to save data in the form of key-value pairs; being persistent means they are not only in memory, but are on disk, stored in non-volatile memory and can be easily queried and written.

Data is stored in XML in all applications; they are ideal for managing user data such as ID, email, authentication status, and other related data. Their implementation and use is very simple.

Key-Value Storage Explained Simply

On Android it is stored in XML; on iOS in UserDefaults; and Flutter abstracts everything so you only work with the same API.

It is ideal for:

  • User session state
  • Configuration preferences
  • Flags like “the user has already seen the onboarding”
  • Small data that do not require a database

When to choose SharedPreferences instead of SQLite or other options

Use it when:

  • Data is simple
  • There are no relationships or complex structures
  • You require speed without spinning up a DB

Don't use it when:

  • You need to store large lists or complex objects
  • Encryption or advanced security is required
  • Your app handles large volumes of data

※ In my academy app, for example, I save simple data such as the user's ID and whether they remain logged in. To load courses or progress, I do use more robust mechanisms there.

⭐ Installation of the SharedPreferences package in Flutter

Add the package to your pubspec.yaml:

dependencies: shared_preferences: ^2.2.0

Then run:

$ flutter pub get

Configuration

No additional configuration is needed. Like all disk read/write systems, operations are asynchronous, so you will use async and await.

Platform Considerations

  • Android: uses XML.
  • iOS/MacOS: integrates with UserDefaults.
  • Web: uses LocalStorage, with certain limitations.
  • Windows/Linux: local storage via FFI.

⭐ How to save and read basic data (String, int, bool, double, lists)

As we indicated before, with SharedPreferences we can write and read (in addition to read), so we have methods for that purpose:

  • getKeys(): Returns all stored keys.
  • get(String key): Returns the value associated with the specified key.
  • getBool(String key): Returns a boolean value associated with the key.
  • getInt(String key): Returns an integer value associated with the key.
  • getDouble(String key): Returns a decimal value (double) associated with the key.
  • getString(String key): Returns a text value (string) associated with the key.
  • getStringList(String key): Returns a list of text values associated with the key.

All methods are the same, but depending on the type of data you want to store, we have a different method, such as numbers, string, among others; as for the methods for writing:

  • setBool(String key, bool value): Saves a boolean value associated with the key.
  • setInt(String key, int value): Saves an integer value associated with the key.
  • setDouble(String key, double value): Saves a decimal value associated with the key.
  • setString(String key, String value): Saves a text value associated with the key.
  • setStringList(String key, List<String> value): Saves a list of text values associated with the key.

Deletion:

  • remove(String key): Removes the key-value pair associated with the specified key.

Also, passing a null value in any of the setters is equivalent to calling remove(key).

Practical Example

Suppose we have a Person class. Let's see how to save an instance of this class in SharedPreferences:

import 'package:shared_preferences/shared_preferences.dart';
class Person {
 final String name;
 final int age;
 Person(this.name, this.age);
}
void savePersonToSharedPreferences(Person person) async {
 final prefs = await SharedPreferences.getInstance();
 prefs.setString('person_name', person.name);
 prefs.setInt('person_age', person.age);
}
Future<Person?> getPersonFromSharedPreferences() async {
 final prefs = await SharedPreferences.getInstance();
 final name = prefs.getString('person_name');
 final age = prefs.getInt('person_age');
 if (name != null && age != null) {
   return Person(name, age);
 }
 return null;
}

The next step is to implement the above, in which we can register and obtain user data; before using it anywhere in the application, we must create the instance:

final prefs = await SharedPreferences.getInstance();

Like all operations, they are asynchronous, which is normal in this type of technology where data is obtained from the disk.

Now, with this object, we can set data with the methods mentioned before, for example, a string:

prefs.setString(key, value);

If it is an object, you can store the data in JSON format:

prefs.setString(key, json.encode(value));

Here is a complete example:

save(String key, value) async {
 final prefs = await SharedPreferences.getInstance();
 prefs.setString(key, json.encode(value));
}

And finally, it allows reading the object or other:

get(String key) async {
 final prefs = await SharedPreferences.getInstance();
 return json.decode(prefs.getString(key));
}

Clear Examples of get/set

prefs.setString('nombre', 'Carlos');
prefs.setInt('edad', 28);
prefs.setBool('logueado', true);

final nombre = prefs.getString('nombre');
final edad = prefs.getInt('edad');
final logueado = prefs.getBool('logueado');

Usage in Asynchronous Operations: Why everything is async

The instance is obtained from the disk or operating system storage. Flutter handles it as a costly operation and therefore requires await.

Common errors

  • Retrieving data before getting the instance.
  • Assuming the value exists (if it doesn't exist, it returns null).
  • Saving excessively large values.

⭐ Saving User Data: Practical Example Based on My Application

In my case, for my academy app, I needed the user to remain connected even if they closed the app, so I saved a couple of essential keys in SharedPreferences:

  • user_id
  • is_logged_in
  • user_email

Saving the user session

Future<void> saveSession(String id, String email) async {
 final prefs = await SharedPreferences.getInstance();
 await prefs.setString('user_id', id);
 await prefs.setString('user_email', email);
 await prefs.setBool('is_logged_in', true);
}

Retrieving data upon app startup

Future<bool> isLoggedIn() async {
 final prefs = await SharedPreferences.getInstance();
 return prefs.getBool('is_logged_in') ?? false;
}

Data cleanup upon logout

Future<void> logout() async {
 final prefs = await SharedPreferences.getInstance();
 await prefs.remove('user_id');
 await prefs.remove('user_email');
 await prefs.setBool('is_logged_in', false);
}

In practice, this allowed students to return to the app and remain connected without requiring constant re-authentication; I use the JSON WEB TOKEN system to also save the user's authentication token.

Good Practices and Limitations of SharedPreferences and when you should NOT use it

  • Do not save large lists or huge objects.
  • Only use JSON for small structures.
  • If you find yourself saving too many things, you probably need Hive or SQLite.
  • passwords
  • private keys

⭐ Frequently Asked Questions (FAQ)

  • Is it safe to use SharedPreferences for passwords?
    • No. Use secure storage.
  • Can I use SharedPreferences on Web?
  • Yes, although it internally uses localStorage and has limitations.
    • Can I save lists or objects?
  • Lists of strings yes; objects → only by using JSON.
  • How do I avoid type errors?
    • By validating null and handling JSON conversions safely.

Conclusion

SharedPreferences is a lightweight, fast, and perfect tool when you only need to save simple data. In my experience creating an academy app, it was key to managing the user session and various preferences without having to spin up databases or more complex systems.

Used judiciously, it is one of the most effective ways to implement local persistence in Flutter.

SharedPreferences are perfect for storing simple data, but if you want to use a real database, we have Flutter's SQLite/SQFlite.

I agree to receive announcements of interest about this Blog.

In this article we will introduce this topic of persistently storing data using SharedPreferences in Flutter, including options, recommendations, and examples.

| 👤 Andrés Cruz

🇪🇸 En español