Realm is a mobile-first, high-performance database designed for real-time data applications. It is particularly useful in mobile apps because of its speed, offline-first capability, and ease of use. In this guide, we’ll show you how to use Realm in Flutter for local data persistence, including setup, CRUD operations (Create, Read, Update, Delete), and handling complex data relationships. We’ll also provide code examples to help you get started.
What is Realm, and Why Use It in Flutter?
Realm is a NoSQL database optimized for mobile devices that allows seamless data storage and real-time updates. Its key advantages include:
- Speed: Realm is designed to be faster than traditional mobile databases like SQLite.
- Offline-First: It stores data locally, allowing your app to work even when there’s no internet connection.
- Real-Time Sync: Realm offers real-time synchronization (in the paid version) that can sync data between devices.
- Zero Boilerplate: Realm manages schema and handles data relationships natively, so you don’t need to write complex SQL queries or schema migrations.
By integrating Realm into your Flutter app, you get a powerful tool to handle your local data efficiently, especially for apps that need fast, reliable offline-first support.
Setting Up Realm in Flutter
Before diving into Realm features, let’s go through the setup process.
Step 1: Add Realm Dependencies
To get the dependency click here and add Realm to your Flutter project by updating your pubspec.yaml
file:
dependencies:
realm: ^20.0.0
Run flutter pub get
to install the package.
Step 2: Import Realm
After adding the dependencies, import the Realm package into your Dart file:
import 'package:realm/realm.dart';
Now, let’s define a Realm schema to structure our data.
Defining a Realm Schema
In Realm, you work with Dart classes that represent your data models. You annotate these classes to define how they should be stored in the database.
Example: Defining a Model Class
Let’s define a Task
model, where each task has an id
, title
, and a completed
status:
import 'package:realm/realm.dart';
// Define a Task model class
class Task extends RealmObject {
@PrimaryKey()
late String id; // Realm automatically handles unique IDs
late String title;
late bool completed;
Task(this.id, this.title, this.completed);
}
Explanation:
-
@PrimaryKey()
: This annotation marksid
as the primary key, ensuring each task has a unique identifier. -
RealmObject
: This is the base class for all Realm model classes. It tells Realm to manage this class as a database object.
Step 3: Open a Realm Instance
Before you can interact with the database, you need to open a Realm instance. Here’s how you can do that:
void main() {
final config = Configuration([Task.schema]); // Pass schema to configuration
final realm = Realm(config); // Open a Realm instance
runApp(MyApp(realm: realm));
}
In this example, Task.schema
is the schema that defines the structure of the data you’ll store. Once the Realm instance is open, you can start working with the data.
Performing CRUD Operations with Realm in Flutter
Now that we have Realm set up, let’s walk through how to perform CRUD (Create, Read, Update, Delete) operations on the data.
1. Creating Data (Inserting)
To add new objects to the database, use the write()
method. Here’s how you can create and insert a new task:
void addTask(Realm realm, String title) {
realm.write(() {
realm.add(Task(ObjectId().toString(), title, false)); // Create a new task
});
}
Explanation:
-
realm.write()
: All database modifications must be wrapped in a write transaction. -
realm.add()
: Adds a new object to the database. -
ObjectId().toString()
: Generates a unique ID for the task.
2. Reading Data (Querying)
To read data from Realm, you can query the database directly by accessing the class type. Here’s how to retrieve all tasks:
List<Task> getAllTasks(Realm realm) {
return realm.all<Task>().toList(); // Get all Task objects from the database
}
You can also filter tasks using queries:
List<Task> getCompletedTasks(Realm realm) {
return realm.query<Task>('completed == true').toList(); // Filter completed tasks
}
Explanation:
-
realm.all<Task>()
: Retrieves all objects of typeTask
from the database. -
realm.query()
: Allows you to filter objects using a query. In this case, we’re filtering for tasks wherecompleted == true
.
3. Updating Data
To update data, retrieve the object and modify its fields inside a write transaction:
void markTaskAsCompleted(Realm realm, Task task) {
realm.write(() {
task.completed = true; // Update the task's status
});
}
Explanation:
- Modifying an object’s fields within a
realm.write()
block automatically updates the object in the database.
4. Deleting Data
To remove data from Realm, use the delete()
method inside a write transaction:
void deleteTask(Realm realm, Task task) {
realm.write(() {
realm.delete(task); // Delete the task from the database
});
}
This removes the specified task from the database.
Working with Relationships
Realm also supports complex data relationships like one-to-many or many-to-many. Here’s an example of a one-to-many relationship where a Project
contains multiple Task
objects.
Example: Defining a One-to-Many Relationship
class Project extends RealmObject {
@PrimaryKey()
late String id;
late String name;
late List<Task> tasks = []; // A list of related tasks
Project(this.id, this.name);
}
To add tasks to a project:
void addTaskToProject(Realm realm, Project project, String taskTitle) {
realm.write(() {
final task = Task(ObjectId().toString(), taskTitle, false);
project.tasks.add(task); // Add task to the project's task list
realm.add(task); // Add task to the Realm database
});
}
With Realm, managing relationships is simple since it treats relationships as part of the object model.
Reactive Data with Realm
One of the standout features of Realm is its ability to provide real-time data updates. You can listen for changes in the data and update the UI accordingly.
Example: Listening for Data Changes
RealmResults<Task> tasks = realm.all<Task>();
StreamBuilder(
stream: tasks.changes,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
final tasks = snapshot.data.results;
return ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) {
final task = tasks[index];
return ListTile(
title: Text(task.title),
trailing: Icon(
task.completed ? Icons.check_box : Icons.check_box_outline_blank,
),
);
},
);
},
);
In this example, we use RealmResults<Task>()
to get a list of tasks and listen for changes using a StreamBuilder
. Whenever data is updated, the UI is automatically refreshed.
Saving and Syncing Data with Realm
If you’re using the paid version of Realm, you can also enable real-time syncing across devices. This allows your app to sync local data with the cloud, ensuring consistency across multiple devices.
Example: Sync Configuration
void main() async {
final config = Configuration.flexibleSync([Task.schema], user: myRealmUser);
final realm = await Realm.open(config);
runApp(MyApp(realm: realm));
}
With this setup, any changes made to the Realm database will automatically sync across all devices that are connected to the same account.
Conclusion
Realm is a powerful database solution for Flutter, offering high performance, real-time data handling, and ease of use. From basic CRUD operations to handling complex data relationships, Realm simplifies data persistence in mobile applications. Its ability to work offline and sync data in real-time makes it an excellent choice for mobile-first applications that require seamless local storage and fast performance.
By following this guide, you should be able to integrate Realm into your Flutter projects with ease and start building robust, offline-first apps.
Happy Coding…!!!
Leave a Reply