Isar Plus

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

Zap

OPFS (Modern)

Chrome, Edge (v102+)

  • Fast, native-like performance
  • Persistent storage
  • Full SQLite compatibility
Database

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 before

Schema 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);
    }
  }
}
@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

BrowserVersionStoragePerformance
Chrome102+OPFSExcellent
Edge102+OPFSExcellent
SafariAllIndexedDBGood
FirefoxAllIndexedDBGood

OPFS provides near-native performance on Chromium browsers!

Best Practices

  1. 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));
    }
  2. Test on Target Platforms

    • Test web builds in different browsers
    • Verify performance on mobile devices
    • Check desktop builds
  3. Handle Platform Differences

    if (kIsWeb) {
      // Web-specific logic
    } else {
      // Native-specific logic
    }
  4. 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