What Is the Importance of the ISAR Database in Flutter: Complete Guide
By Braincuber Team
Published on May 14, 2026
ISAR is a modern, cross-platform NoSQL database built specifically for Flutter and Dart. Written in Rust and compiled to native binaries, it delivers exceptional performance for local data storage while offering a fully type-safe query API, real-time reactive streams, and zero-boilerplate schema generation. This complete tutorial is a step by step guide to understanding the importance of the ISAR database in Flutter development. Whether you are building a productivity app, an enterprise tool, or an offline-first mobile solution, this beginner guide covers everything from setup and collections to queries, indexes, and reactive streams with real-world Flutter examples.
What You'll Learn:
- Why ISAR matters for mobile developers and when to use it over alternatives
- How to set up ISAR in a Flutter project with proper dependencies
- How to define collections with auto-generated schema code
- How to use field types, embedded objects, and indexes
- How to open and configure the ISAR database at app startup
- How to perform CRUD operations with write transactions
- How to build type-safe queries with filtering, sorting, and pagination
- How to implement reactive streams for real-time UI updates
- How to build a complete offline attendance tracker with sync logic
Why ISAR Matters for Mobile Developers
Most Flutter apps eventually need local caching, offline-first logic, or high-frequency writes. ISAR was purpose-built for exactly this. It runs on Android, iOS, macOS, Linux, and Windows with native performance on every platform. Note that Flutter Web is not supported by ISAR. Mastering ISAR helps you build offline-first apps that sync automatically when connectivity is restored, query large datasets without blocking the UI thread, replace SharedPreferences or Hive wherever complex querying is needed, eliminate boilerplate with auto-generated schema code via build_runner, and auto-update UI using reactive streams when data changes.
Prerequisites
| Requirement | Details |
|---|---|
| Flutter SDK | Version 3.x or later recommended |
| Dart SDK | Compatible with Dart 3.x project |
| Async Knowledge | Basic understanding of async/await in Dart |
| Code Generation | Familiarity with build_runner and code generation |
Setting Up ISAR in Flutter
Add the required packages to your pubspec.yaml file. ISAR uses isar_flutter_libs to bundle native binaries, which is required for Flutter mobile and desktop apps. Pure Dart projects use a different setup.
dependencies:
isar: ^3.1.0
isar_flutter_libs: ^3.1.0
path_provider: ^2.0.0
dev_dependencies:
isar_generator: ^3.1.0
build_runner: ^2.4.0
Install the packages by running flutter pub get. After defining your collection classes, generate the schema code with dart run build_runner build.
ISAR Collections: The Data Blueprint
In ISAR, a Collection is the equivalent of a database table. Each collection maps to a Dart class annotated with @collection. ISAR auto-generates all schema metadata and typed query extensions from this annotation. Common use-case collections in an enterprise Flutter app include Employee for HR data, AttendanceRecord for clock-in and out times, LeaveRequest for leave management, Payslip for salary breakdown, and SaleOrder for order tracking.
Defining a Collection
Each collection must include the part directive pointing to its generated file. The example below defines an Employee collection with auto-increment ID, name, role, department, active status, and an indexed email field.
import 'package:isar/isar.dart';
part 'employee.g.dart';
@collection
class Employee {
Id id = Isar.autoIncrement;
late String name;
late String role;
late String department;
bool isActive = true;
@Index(type: IndexType.value)
late String email;
}
ISAR Field Types and Embedded Objects
Fields define the data a collection holds. ISAR supports a rich set of native Dart types with automatic serialization and no manual mapping required. Supported types include int for 64-bit integers, double for floating-point values, bool for flags, String for UTF-8 text with full-text indexing support, DateTime stored as UTC microseconds, List of supported primitives, and embedded objects for nested schemas.
| Dart Type | ISAR Type | Notes |
|---|---|---|
| int | Long | 64-bit integer; use for IDs and counts |
| double | Double | Floating-point; suitable for prices and GPS coords |
| bool | Bool | true / false flags |
| String | String | UTF-8 text; supports full-text indexing |
| DateTime | DateTime | Stored as UTC microseconds internally |
| List<T> | List | Lists of any supported primitive type |
| Embedded Object | Object | Nested schema with no foreign key needed |
Embedded Objects
ISAR supports embedding sub-objects directly inside a collection using the @embedded annotation. These are ideal for nested address, location, or metadata structures with no join required. The embedded object is stored inline within the parent record.
@embedded
class Address {
late String street;
late String city;
late String country;
}
@collection
class Employee {
Id id = Isar.autoIncrement;
late String name;
Address? address; // Embedded inline, no join
}
Indexes
Indexes speed up query performance on frequently filtered or sorted fields. Declare them using the @Index annotation. ISAR supports three index types: IndexType.value for exact match and range queries, IndexType.hash for equality-only lookups on Strings with faster writes, and IndexType.hashElements for List fields that index each element individually.
@collection
class AttendanceRecord {
Id id = Isar.autoIncrement;
@Index(type: IndexType.value)
late int employeeId;
@Index(type: IndexType.hash, composite: [CompositeIndex('date')])
late String status;
late DateTime date;
DateTime? clockIn;
DateTime? clockOut;
}
Opening the ISAR Database
ISAR must be opened once at app startup, and the instance reused throughout the app lifecycle. This is typically done inside main() or a top-level provider. During development, ISAR provides a built-in browser-based Inspector that lets you browse collections, run queries, and inspect records live. Open http://localhost:8080 in your browser while the app is running on a simulator or emulator.
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
late Isar isar;
Future initIsar() async {
final dir = await getApplicationDocumentsDirectory();
isar = await Isar.open(
[EmployeeSchema, AttendanceRecordSchema],
directory: dir.path,
name: 'appDatabase',
);
}
Call initIsar() before runApp() in your main function to ensure the database is ready before the UI starts.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initIsar();
runApp(const MyApp());
}
CRUD Operations
All write operations in ISAR must run inside a write transaction. Reads are performed freely without a transaction. The put() method inserts or updates a record by its Id. The get() method fetches a single record by ID. Filter queries allow retrieving records matching specific conditions. The delete() and deleteAll() methods remove records individually or in bulk.
// Create or Update
Future saveEmployee(Employee employee) async {
await isar.writeTxn(() async {
await isar.employees.put(employee);
});
}
// Read by ID
Future getEmployeeById(int id) async {
return await isar.employees.get(id);
}
// Read with filter
Future> getActiveEmployees() async {
return await isar.employees
.filter()
.isActiveEqualTo(true)
.findAll();
}
// Delete by ID
Future deleteEmployee(int id) async {
await isar.writeTxn(() async {
await isar.employees.delete(id);
});
}
// Delete with filter
Future deleteInactive() async {
await isar.writeTxn(() async {
await isar.employees
.filter()
.isActiveEqualTo(false)
.deleteAll();
});
}
Querying Data with the Filter Builder
ISAR provides a type-safe query builder that compiles to native queries with no raw SQL, no string-based parsing, and no runtime errors from typos. The filter builder supports equality, contains, range, greater than or less than comparisons, chained AND and OR conditions, negation, and list contains operations.
| Operation | Example Method | Description |
|---|---|---|
| Equality | .nameEqualTo('Ali') | Exact match on field |
| Contains | .nameContains('ahmed') | Substring search |
| Range | .salaryBetween(3000, 8000) | Between two values |
| Greater / Less | .salaryGreaterThan(5000) | Comparison operators |
| AND | .and() | Chained AND conditions |
| OR | .or() | Chained OR conditions |
| Not | .not() | Negate the next filter |
| List Contains | .tagsAnyEqualTo('flutter') | Match inside a List field |
Chained Filter and Pagination Example
// Filter late arrivals for a specific employee in a date range
Future> getLateArrivals({
required int employeeId,
required DateTime from,
required DateTime to,
}) async {
return await isar.attendanceRecords
.filter()
.employeeIdEqualTo(employeeId)
.and()
.statusEqualTo('late')
.and()
.dateBetween(from, to)
.sortByDateDesc()
.findAll();
}
// Paginated query
final records = await isar.attendanceRecords
.filter()
.offset(0)
.limit(20)
.sortByDateDesc()
.findAll();
Reactive Streams for Real-Time UI Updates
One of ISAR most powerful Flutter features is its built-in reactive stream support. Watch a collection or a filtered query and rebuild widgets automatically whenever the underlying data changes. This is ideal for real-time dashboards, attendance trackers, or live order lists.
// Watch entire collection
Stream watchEmployees() {
return isar.employees.watchLazy();
}
// Watch filtered query with initial data
Stream> watchTodayAttendance() {
final today = DateTime.now();
final start = DateTime(today.year, today.month, today.day);
final end = start.add(const Duration(days: 1));
return isar.attendanceRecords
.filter()
.dateBetween(start, end)
.watch(fireImmediately: true);
}
// Use with StreamBuilder
StreamBuilder>(
stream: watchTodayAttendance(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
final records = snapshot.data!;
return ListView.builder(
itemCount: records.length,
itemBuilder: (context, index) => ListTile(
title: Text('Employee: ${records[index].employeeId}'),
subtitle: Text('Status: ${records[index].status}'),
),
);
},
)
Real-World Example: Offline Attendance Tracker
The following complete example combines collections, write transactions, queries, and streams into a practical offline attendance tracker. This pattern store locally first, sync later is the backbone of any robust offline-first Flutter integration with backend systems like Odoo.
class AttendanceRepository {
final Isar isar;
AttendanceRepository(this.isar);
// 1. Clock In
Future clockIn(int employeeId) async {
final record = AttendanceRecord()
..employeeId = employeeId
..checkIn = DateTime.now()
..status = 'present'
..synced = false;
await isar.writeTxn(() async {
await isar.attendanceRecords.put(record);
});
}
// 2. Clock Out
Future clockOut(int recordId) async {
await isar.writeTxn(() async {
final record = await isar.attendanceRecords.get(recordId);
if (record != null) {
record.checkOut = DateTime.now();
await isar.attendanceRecords.put(record);
}
});
}
// 3. Get unsynced records to push to backend
Future> getUnsynced() async {
return await isar.attendanceRecords
.filter()
.syncedEqualTo(false)
.findAll();
}
// 4. Mark records as synced after successful push
Future markSynced(List ids) async {
await isar.writeTxn(() async {
final records = await isar.attendanceRecords.getAll(ids);
for (final r in records) {
if (r != null) {
r.synced = true;
await isar.attendanceRecords.put(r);
}
}
});
}
// 5. Watch live attendance stream
Stream> watchAttendance(int employeeId) {
return isar.attendanceRecords
.filter()
.employeeIdEqualTo(employeeId)
.watch(fireImmediately: true);
}
}
Offline-First Pattern Note
The synced flag pattern enables a background service to push pending records whenever network connectivity is restored. This store locally first, sync later approach ensures data is never lost even when the device is offline. Although official ISAR development has slowed as of 2026, the isar_community fork continues to offer ongoing updates and improvements.
Type-Safe Auto-Generated Schema
ISAR generates all schema code from Dart class annotations, eliminating manual mapping and runtime errors. The typed query builder catches mistakes at compile time.
Reactive UI Without Boilerplate
Built-in watchers and streams let you rebuild Flutter widgets automatically when data changes. No need for manual state management or polling.
Native Cross-Platform Performance
Written in Rust and compiled to native binaries, ISAR delivers consistent high performance across Android, iOS, macOS, Linux, and Windows.
Embedded Objects and Indexes
Store nested data structures without joins using @embedded objects. Speed up queries with @Index annotations supporting value, hash, and composite indexes.
Frequently Asked Questions
What is ISAR database and why use it in Flutter?
ISAR is a cross-platform NoSQL database written in Rust, purpose-built for Flutter and Dart. It offers native performance, type-safe queries, auto-generated schema, and reactive streams. Use it when you need local caching, offline-first support, or complex querying beyond what SharedPreferences or Hive provide.
How does ISAR handle write operations?
All write operations in ISAR must run inside a write transaction using isar.writeTxn(). This ensures atomic multi-record writes and data integrity even if the app crashes during a write. The put() method handles both insert and update based on whether the Id already exists.
Does ISAR support web platforms in Flutter?
No, ISAR does not support Flutter Web. It compiles to native binaries via Dart FFI, which is not available in web environments. For web Flutter apps, alternatives like Hive or Drift (formerly Moor) may be more suitable.
How do indexes work in ISAR database?
ISAR supports three index types: IndexType.value for exact match and range queries, IndexType.hash for fast equality lookups on strings, and IndexType.hashElements for indexing individual list elements. Indexes are declared using the @Index annotation and composite indexes are supported for multi-field lookups.
Can ISAR be used for offline-first mobile apps?
Yes. ISAR is ideal for offline-first architectures. The recommended pattern is to store data locally first using a synced boolean flag, then push pending records to a backend service when connectivity is restored. Reactive streams enable real-time UI updates from local data without network dependency.
Need Help with Flutter and ISAR?
Our mobile development experts can help you integrate ISAR database into your Flutter app, design offline-first architectures, implement reactive data streams, and build enterprise-grade mobile solutions with local data persistence.
