🧩 shared_pref_builder
Generate strongly-typed SharedPreferences accessors in Flutter — without
build_runner.
shared_pref_builder lets you define your app preferences as a simple Dart class using annotations,
and automatically generates type-safe, easy-to-use getters and setters.
No build_runner, no boilerplate — just run dart run shared_pref_builder.
🚀 Features
- ⚡ No build_runner required — runs instantly via a CLI command.
- 🧠 Type-safe accessors —
- Primitive types supports
int,double,bool,String,List<String>. - Type-safe JSON — supports
Map<dynamic, dynamic>andList<dynamic>. - Type-safe custom conversion — supports custom data model with
@SPField(from: , to: )annotation.
- Primitive types supports
- ⚙️ Optional configuration in
pubspec.yamlfor faster, targeted generation.
📦 Installation
Use as global package (recommended)
dart pub global activate shared_pref_builder
or
Add this to your dev_dependencies in pubspec.yaml
dev_dependencies:
shared_pref_builder: (latest version)
Add the annotation package to your dependencies in pubspec.yaml
dependencies:
shared_pref_annotation: (latest version)
⚙️ Configuration (recommended)
You can specify which file contains your annotated preferences class to improve performance:
shared_pref_builder:
path: lib/core/app_pref.dart
If path is not provided, the generator will scan all files inside the lib/ directory.
🧠 Usage
1️⃣ Annotate your preferences class
// lib/core/sp.dart
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_pref_annotation/shared_pref_annotation.dart';
@SharedPref()
class AppPref {
String? token;
/// With default value
bool isDarkMode = false;
}
2️⃣ Run the generator
If using as a global dart package, run:
shared_pref_builder
and if using as a dev_dependency, run:
dart run shared_pref_builder
This will generate a file next to your class:
extension AppPrefSpExt on SharedPreferences {
SPValue<String> get token => SPValue<String>(
key: 'token',
getter: getString,
setter: setString,
remover: remove,
);
SPWithDefault<bool> get isDarkMode => SPWithDefault<bool>(
key: 'isDarkMode',
getter: getBool,
setter: setBool,
remover: remove,
defaultValue: false,
);
}
⚡ Use with Custom Data Model class
Your data class
class User {
const User({required this.name, required this.email});
final String name;
final String email;
Map<String, dynamic> toMap() => {'name': name, 'email': email};
factory User.fromMap(Map<String, dynamic> map) {
return User(name: map['name'] ?? '', email: map['email'] ?? '');
}
String toJson() => json.encode(toMap());
factory User.fromJson(String source) => User.fromMap(json.decode(source));
static String toJsonString(User i) => i.toJson(); // <- custom converter
}
in app_pref.dart
@sharedPref
class AppPref {
@SPField(from: User.fromJson, to: User.toJsonString)
User? userData;
}
⚠️ NOTE
- The method used in
frommust return the same class and should have only one positional String parameter. - The method used in
tomust return a String and should have only one positional parameter and type of the same class.
🧩 Using Generated Accessors
final prefs = await SharedPreferences.getInstance();
// Read
final token = prefs.token.value;
// Write
await prefs.token.setValue('NEW-TOKEN');
// Remove
await prefs.token.remove();
🧱 Example Project Structure
lib/
┣ core/
┃ ┗ app_pref.dart
┣ main.dart
pubspec.yaml
Generated:
lib/
┣ core/
┃ ┣ app_pref.dart
┃ ┗ app_pref_gen.dart
🙌 Contributing
Fill free to create an issue or open a pull request to contribute.
❤️ Credits
Developed with 💙 by Ahnaf Sakil
Inspired by simplicity — built for real-world Flutter projects.
📄 License
BSD 3-Clause License. See LICENSE for details.