Limitations
Platform-specific limitations and constraints
Limitations
Isar Plus works across mobile, desktop, and web platforms. Each platform has different characteristics and limitations.
Platform Overview
Platforms: iOS, Android, macOS, Linux, Windows
Limitations
- String prefix where-clauses limited to first 1024 bytes
- Maximum object size: 16MB
VM platforms have minimal limitations and full feature support!
Platforms: Chrome, Firefox, Safari, Edge
Storage Backends
OPFS (Modern)
Chrome, Edge (v102+)
- Fast, native-like performance
- Persistent storage
- Full SQLite compatibility
IndexedDB (Fallback)
Safari, Firefox, older browsers
- Some limitations apply
- Slower than OPFS
- Good compatibility
Note on OPFS: OPFS provides the highest performance but requires the database to run in a Web Worker environment. Because Isar Plus Web support currently runs on the main thread, it temporarily falls back to IndexedDB under the hood in most environments. Full OPFS Web Worker support is planned for a future update!
Limitations
// ❌ Async operations not supported on web (require isolates)
await isar.writeAsync((isar) => isar.users.put(user));
await isar.users.getAsync(1);
// ❌ Watchers not supported on web
isar.users.watchLazy().listen((_) {});
isar.users.watchObject(1).listen((user) {});
// ✅ Use sync APIs on web
isar.write((isar) => isar.users.put(user));
final user = isar.users.get(1);Async operations require isolates which are not available on web. Use synchronous APIs instead!
General Limitations
- No support for very large transactions (keep under 100MB)
- Links are lazy-loaded (small overhead on first access)
- Embedded objects cannot contain other embedded objects (single level only)
VM Limitations
String Indexing
Only the first 1024 bytes of a string are indexed:
@collection
class Article {
Id? id;
@Index()
late String title; // ✅ Usually fine
@Index()
late String content; // ⚠️ Only first 1024 bytes indexed
}For full-text search on long strings, use the multi-entry index pattern.
Object Size
Maximum object size is 16MB:
@collection
class LargeDocument {
Id? id;
// ⚠️ Be careful with large data
late List<int> fileData;
}Store large files outside of Isar and keep only references in the database.
Web Limitations
API Compatibility
// ❌ Async transactions (require isolates)
await isar.readAsync((isar) => isar.users.get(1));
await isar.writeAsync((isar) => isar.users.put(user));
await isar.users.getAsync(1);
await isar.users.getAllAsync([1, 2, 3]);
// ❌ Watchers (require native isolates)
isar.users.watchLazy().listen((_) {});
isar.users.watchObject(1).listen((user) {});
isar.users.watchDetailed().listen((change) {});
// ❌ Text operations
Isar.splitWords('hello world');
isar.users.where().nameMatches('pattern*');// ✅ Synchronous operations (use these on web)
final user = isar.users.get(1);
final users = isar.users.getAll([1, 2, 3]);
isar.write((isar) => isar.users.put(user));
isar.read((isar) => isar.users.where().findAll());
// ✅ Filters and queries
isar.users.where()
.nameContains('John')
.findAll();
// ✅ Where clauses
isar.users.where()
.nameEqualTo('John')
.findAll();IndexedDB Fallback Limitations
When OPFS is not available, IndexedDB fallback has additional limitations:
// ⚠️ Return values may differ
await isar.writeAsync((isar) async {
final count = isar.users.deleteAll([1, 2, 3]);
// OPFS: returns exact count
// IndexedDB: may return different value
});
// ⚠️ Auto-increment not reset by clear()
await isar.writeAsync((isar) async {
isar.users.clear();
});
// On OPFS: next ID is 1
// On IndexedDB: next ID continues from beforeSchema Migrations
// ⚠️ Less strict validation on web
@collection
class User {
Id? id;
late String name;
// Changing type is less validated
late int age; // was String before
}Double-check schema changes on web during releases!
Text Operations
// ❌ Not available on web
final words = Isar.splitWords('Hello World');
// ❌ Wildcard matching not available
await isar.users.where()
.nameMatches('John*')
.findAll();
// ✅ Use alternative patterns
await isar.users.where()
.nameStartsWith('John')
.findAll();
await isar.users.where()
.nameContains('John')
.findAll();Workarounds
Large Strings
// Instead of indexing entire content
@collection
class Article {
Id? id;
late String title;
late String content;
// Create searchable keywords
@Index(type: IndexType.value)
late List<String> keywords;
}
// Generate keywords before saving
final article = Article()
..title = 'My Article'
..content = 'Long content...'
..keywords = generateKeywords(content);File Storage
@collection
class Document {
Id? id;
late String name;
// Store file path, not content
late String filePath;
late int fileSize;
}
// Store actual file separately
final file = File('path/to/file.pdf');
final document = Document()
..name = 'Document'
..filePath = file.path
..fileSize = await file.length();Web Async Pattern
// Platform-specific code for async operations
class IsarHelper {
static Future<User?> getUser(Isar isar, int id) async {
if (kIsWeb) {
// Web: use sync API
return isar.users.get(id);
} else {
// Native: can use async for background processing
return isar.users.getAsync(id);
}
}
}Cross-Platform Text Search
@collection
class Product {
Id? id;
late String name;
// Store lowercase for case-insensitive search
@Index(caseSensitive: false)
late String searchName;
}
// Before saving
product.name = 'iPhone 15 Pro';
product.searchName = product.name.toLowerCase();
// Query works on all platforms
await isar.products
.where()
.searchNameContains('iphone')
.findAll();Platform Detection
import 'package:flutter/foundation.dart';
void configureIsar() {
if (kIsWeb) {
print('Running on web with limitations');
// Use async-only APIs
} else {
print('Running on native platform');
// Can use sync APIs for performance
}
}Browser Support
| Browser | Version | Storage | Performance |
|---|---|---|---|
| Chrome | 102+ | OPFS | Excellent |
| Edge | 102+ | OPFS | Excellent |
| Safari | All | IndexedDB | Good |
| Firefox | All | IndexedDB | Good |
OPFS provides near-native performance on Chromium browsers!
Best Practices
-
Write Cross-Platform Code
// ✅ Sync works everywhere isar.write((isar) => isar.users.put(user)); final user = isar.users.get(1); // ⚠️ Async only works on native (mobile/desktop) // Throws UnsupportedError on web await isar.writeAsync((isar) => isar.users.put(user));// Platform-aware pattern if (kIsWeb) { isar.write((isar) => isar.users.put(user)); } else { await isar.writeAsync((isar) => isar.users.put(user)); } -
Test on Target Platforms
- Test web builds in different browsers
- Verify performance on mobile devices
- Check desktop builds
-
Handle Platform Differences
if (kIsWeb) { // Web-specific logic } else { // Native-specific logic } -
Keep Objects Small
// Store references, not large data @collection class Photo { Id? id; late String url; // Not the image bytes late String thumbnailUrl; }
Migration Notes
When migrating from Isar 3:
Isar Plus uses SQLite instead of LMDB. Some behaviors may differ slightly.
See the Migration Guide for details.
Next Steps
Last Update