open static method

Future<Database> open(
  1. String path, {
  2. String? encryptionKey,
})

Opens or creates a SQLite database at path.

final db = await Database.open('app.db');

If the file at path does not exist, a new database is created. Reader and writer isolates are spawned non-blocking during open — the first query awaits their readiness automatically.

If encryptionKey is provided, the database is encrypted using SQLite3 Multiple Ciphers (AES-256). The key must be a hex-encoded string (64 hex chars for a 256-bit key). All connections (writer + reader pool) use the same key.

final db = await Database.open(
  'secure.db',
  encryptionKey: '0123456789abcdef0123456789abcdef'
      '0123456789abcdef0123456789abcdef',
);

Throws a ResqliteConnectionException if the file cannot be opened or the encryption key is incorrect.

The returned Database must be closed with close when no longer needed to release native resources.

Implementation

static Future<Database> open(String path, {String? encryptionKey}) async {
  final pathNative = path.toNativeUtf8();
  final keyNative = encryptionKey != null
      ? encryptionKey.toNativeUtf8()
      : ffi.nullptr.cast<Utf8>();
  try {
    // Determine the number of reader isolates to spawn.
    // cores - 1: leave one core for the main isolate (UI thread in Flutter).
    // min 2: so one worker sacrifice doesn't leave zero capacity.
    // max 4: benchmarked 2/4/8 workers — concurrent query throughput plateaus
    //   at 4. Each idle worker costs ~30KB + one C reader connection.
    final readerCount = (Platform.numberOfProcessors - 1).clamp(2, 4);

    final handle = resqliteOpen(pathNative, readerCount, keyNative);
    if (handle == ffi.nullptr) {
      throw ResqliteConnectionException(
        'Failed to open database at "$path"'
        '${encryptionKey != null ? ' (check encryption key)' : ''}',
      );
    }

    return Database._(handle, readerCount);
  } finally {
    calloc.free(pathNative);
    if (encryptionKey != null) calloc.free(keyNative);
  }
}