Schema
Define your data models with Isar collections
Schema
When you use Isar to store your app's data, you're dealing with collections. A collection is like a database table and can only contain a single type of Dart object.
Anatomy of a Collection
You define each Isar collection by annotating a class with @collection or @Collection().
@collection
class User {
Id? id;
String? firstName;
String? lastName;
}To persist a field, Isar must have access to it. Make it public or provide getter and setter methods.
Data Types
Isar supports the following data types:
Primitive Types
@collection
class PrimitiveTypes {
PrimitiveTypes(this.id);
final int id;
bool? boolValue;
int? intValue;
double? doubleValue;
DateTime? dateValue;
String? stringValue;
}Lists
@collection
class ListTypes {
ListTypes(this.id);
final int id;
List<bool>? boolList;
List<int>? intList;
List<double>? doubleList;
List<DateTime>? dateList;
List<String>? stringList;
}Lists cannot contain null values. Use nullable types instead.
Enums
Isar Plus supports Dart enums with two storage strategies:
By default, enums are stored by their index (ordinal). Simply use the enum directly without any annotation:
enum Status { active, inactive, pending }
@collection
class Task {
Task(this.id);
final int id;
Status? status; // Stored as 0, 1, or 2
}The stored values are:
Status.active→0Status.inactive→1Status.pending→2
If you reorder enum values, existing stored data will map to different enum values. Add new values at the end or use custom values for stability.
For more control, define a field in your enum and annotate it with @enumValue. This field's value will be used for storage:
enum Status {
active(1),
inactive(2),
pending(3);
const Status(this.code);
@enumValue
final int code;
}
@collection
class Task {
Task(this.id);
final int id;
Status? status; // Stored as 1, 2, or 3
}Supported types for @enumValue:
byte- stored as single byteshort- stored as 16-bit integerint- stored as 32-bit integerString- stored as text
// String-based enum example
enum Priority {
low('LOW'),
medium('MEDIUM'),
high('HIGH');
const Priority(this.name);
@enumValue
final String name;
}Migration from Isar v3
The @enumerated and @Enumerated(EnumType.ordinal/name) annotations from
Isar v3 are no longer available. Use plain enums for ordinal storage or
@enumValue for custom values.
Embedded Objects
@embedded
class Address {
String? street;
String? city;
String? country;
}
@collection
class Person {
Person(this.id);
final int id;
String? name;
Address? address;
List<Address>? addresses;
}Ids
Every collection needs an Id field to uniquely identify objects.
@collection
class User {
User(this.id);
final int id;
String? name;
}For auto-incrementing IDs, use the collection.autoIncrement() method when inserting:
isar.write((isar) {
final user = User(isar.users.autoIncrement());
isar.users.put(user);
});Custom IDs
@collection
class User {
User(this.id);
final int id; // You manage the ID
String? name;
}Field Annotations
@Index
Create indexes for better query performance:
@collection
class User {
User(this.id);
final int id;
@Index()
String? email;
@Index(type: IndexType.value)
String? username;
@Index(caseSensitive: false)
String? name;
}@Ignore
Exclude fields from storage:
@collection
class User {
User(this.id);
final int id;
String? name;
@ignore
String? temporaryData; // Not stored
}@Name
Rename fields in the database:
@collection
class User {
User(this.id);
final int id;
@Name("user_name")
String? name;
}@Size
Limit string size:
@collection
class User {
User(this.id);
final int id;
@Size(max: 100)
String? shortText;
@Size(max: 1000)
String? longText;
}Composite Indexes
Create indexes on multiple fields:
@collection
@Index(composite: ['lastName', 'age'])
class User {
User(this.id);
final int id;
String? firstName;
String? lastName;
int? age;
}Modeling Relationships
Isar Plus v4 models relationships with embedded objects or manual ID fields instead of runtime link types. See the dedicated Relationships page for concrete examples lifted from the codebase.
Migration
Isar handles schema migrations automatically in most cases:
- Adding new fields
- Removing fields
- Changing field types (with data loss)
- Adding/removing indexes
Changing the type of an existing field will result in data loss for that field.
Next Steps
Last Update