When building Flutter applications, managing local data efficiently is critical. You want a database that is lightweight, fast, and easy to integrate, especially if your app will work offline. Isar is one such database. It is a high-performance, easy-to-use NoSQL embedded database tailored for Flutter. With features like reactive queries, indexes, relationships, migrations, and transactions, Isar makes local data persistence both powerful and developer-friendly.

In this article, you’lll learn how to integrate Isar into a Flutter project, set up a data model, and perform the full range of CRUD (Create, Read, Update, Delete) operations. To make this practical, you’ll build a simple to-do app that allows users to create, view, update, and delete tasks.

Prerequisites

Before starting, ensure you have the following:

  1. Flutter SDK installed (version 3.0 or above recommended).
    Check your version with:

     flutter --version 
  2. Dart knowledge: Familiarity with Dart syntax, classes, and async programming.

  3. Flutter basics: You should know how to set up a Flutter project, build widgets, and use FutureBuilder or setState for state management.

  4. Code editor: VS Code or Android Studio is recommended.

If these are in place, we are ready to begin.

What We Are Building

We will create a Task Manager App that lets users:

  • Add new tasks.

  • View all tasks in a list.

  • Update existing tasks.

  • Delete tasks.

By the end, you will have a fully functioning CRUD app built with Flutter and Isar.

How to Set Up Isar in a Flutter Project

Step 1: Add dependencies

Open your pubspec.yaml file and add the following:

dependencies: flutter: sdk: flutter isar: ^3.1.0 isar_flutter_libs: ^3.1.0 dev_dependencies: isar_generator: ^3.1.0 build_runner: any 
  • isar: The core Isar package.

  • isar_flutter_libs: Required for Flutter integration.

  • isar_generator: Used to generate code for your models.

  • build_runner: Runs the code generator.

Run:

flutter pub get 

Step 2: Create and initialize Isar

Create a file named isar_setup.dart. This will handle the opening of the Isar database.

import 'package:isar/isar.dart'; import 'package:path_provider/path_provider.dart'; import 'task.dart'; // we will create this model soon late final Isar isar; Future<void> initializeIsar() async { final dir = await getApplicationDocumentsDirectory(); isar = await Isar.open( [TaskSchema], directory: dir.path, ); } 

Explanation:

  • getApplicationDocumentsDirectory() provides a storage location for the database file.

  • Isar.open() initializes the database and registers our Task schema.

  • late final Isar isar; ensures we can access the database instance globally after initialization.

How to Create the Task Model

Now let’s define our data model for tasks. Create a file named task.dart.

import 'package:isar/isar.dart'; part 'task.g.dart'; @Collection() class Task { Id id = Isar.autoIncrement; // auto-incrementing primary key late String name; late DateTime createdAt; Task(this.name) : createdAt = DateTime.now(); } 

Explanation:

  • @Collection() tells Isar this class represents a database collection.

  • Id id = Isar.autoIncrement; creates a unique identifier automatically.

  • late String name; stores the task name.

  • late DateTime createdAt; stores the creation timestamp.

  • part 'task.g.dart'; links to the generated code, which will be created after running the code generator.

Generate the code with:

flutter pub run build_runner build 

This generates task.g.dart, which contains the necessary schema code.

How to Build the Repository for CRUD Operations

Create a new file called task_repository.dart. This will house the methods for interacting with the database.

import 'package:isar/isar.dart'; import 'task.dart'; import 'isar_setup.dart'; class TaskRepository { Future<void> addTask(String name) async { final task = Task(name); await isar.writeTxn(() async { await isar.tasks.put(task); }); } Future<List<Task>> getAllTasks() async { return await isar.tasks.where().findAll(); } Future<void> updateTask(Task task) async { await isar.writeTxn(() async { await isar.tasks.put(task); }); } Future<void> deleteTask(Task task) async { await isar.writeTxn(() async { await isar.tasks.delete(task.id); }); } } 

Explanation:

  • addTask: Creates a new task and saves it.

  • getAllTasks: Reads all tasks from the database.

  • updateTask: Updates an existing task by calling .put() again.

  • deleteTask: Removes a task by its id.

  • isar.writeTxn: Ensures operations run inside a transaction for safety and consistency.

How to Integrate CRUD into the Flutter UI

Now, let’s connect everything inside main.dart.

import 'package:flutter/material.dart'; import 'isar_setup.dart'; import 'task_repository.dart'; import 'task.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await initializeIsar(); // initialize Isar before runApp runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: TaskListScreen(), ); } } class TaskListScreen extends StatefulWidget { @override _TaskListScreenState createState() => _TaskListScreenState(); } class _TaskListScreenState extends State<TaskListScreen> { final TaskRepository _taskRepository = TaskRepository(); late Future<List<Task>> _tasksFuture; @override void initState() { super.initState(); _tasksFuture = _taskRepository.getAllTasks(); } Future<void> _addTask() async { await _taskRepository.addTask('New Task'); setState(() { _tasksFuture = _taskRepository.getAllTasks(); }); } Future<void> _deleteTask(Task task) async { await _taskRepository.deleteTask(task); setState(() { _tasksFuture = _taskRepository.getAllTasks(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Isar CRUD Example')), body: FutureBuilder<List<Task>>( future: _tasksFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else { final tasks = snapshot.data ?? []; if (tasks.isEmpty) { return Center(child: Text('No tasks yet.')); } return ListView.builder( itemCount: tasks.length, itemBuilder: (context, index) { final task = tasks[index]; return ListTile( title: Text(task.name), subtitle: Text('Created at: ${task.createdAt}'), trailing: IconButton( icon: Icon(Icons.delete), onPressed: () => _deleteTask(task), ), ); }, ); } }, ), floatingActionButton: FloatingActionButton( onPressed: _addTask, child: Icon(Icons.add), ), ); } } 

Explanation:

  • initializeIsar(): Ensures the database is ready before the app runs.

  • _tasksFuture: Holds a future of the list of tasks.

  • _addTask: Adds a new task and refreshes the list.

  • _deleteTask: Deletes a task and refreshes the list.

  • FutureBuilder: Automatically rebuilds the UI when the future completes.

  • ListView.builder: Displays all tasks dynamically.

This gives you a simple yet complete CRUD app using Isar.

Beyond CRUD: Advanced Features of Isar

Once you are comfortable with CRUD, Isar provides advanced tools to optimize and extend your application:

  1. Reactive Queries:
    Instead of using FutureBuilder, you can listen for changes directly.

     final stream = isar.tasks.where().watch(fireImmediately: true); 
  2. Indexes:
    Improve query performance by indexing fields.

     @Collection() class Task { Id id = Isar.autoIncrement; @Index() late String name; } 
  3. Relations:
    Link one collection to another (for example, Project with many Tasks).

  4. Custom Queries:
    Perform complex filtering, sorting, and pagination.

  5. Migrations:
    Safely evolve your schema as the app grows.

  6. Batch Operations:
    Insert or update many records in one transaction.

Conclusion

We built a simple Flutter to-do app with Isar that supports creating, reading, updating, and deleting tasks. Along the way, we learned how to:

  1. Add Isar dependencies.

  2. Define a model with annotations.

  3. Generate schema code.

  4. Implement CRUD operations in a repository.

  5. Connect Isar to the Flutter UI.

With its performance, developer-friendly API, and advanced features, Isar is an excellent choice for local persistence in Flutter applications.

For further learning, consult the official docs:

  1. Isar on pub.dev

  2. Isar documentation


Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More.


Leave a Reply

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.