> ## Documentation Index
> Fetch the complete documentation index at: https://cindel.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Cindel on Flutter Web: SQLite, OPFS, and Browser Storage

> Run Cindel in Flutter Web with SQLite and OPFS. Configure a logical DB name, meet browser requirements, and handle storage quota errors.

Cindel runs in Flutter Web apps using the same typed API you use on native platforms. You open a database, register your generated schemas, and work through typed collections like `db.todos` — no code changes required when moving between native and web targets. The key difference is that the `directory` parameter becomes a logical browser database name rather than a filesystem path, and Cindel uses a SQLite/OPFS backend instead of MDBX, which is not available in browsers.

## Required Dependencies

Add both `cindel` and `cindel_flutter_libs` to your `pubspec.yaml`. The `cindel_flutter_libs` package bundles the Web worker, JavaScript glue, and Wasm runtime that Cindel needs to run in the browser. Your Dart code only imports `package:cindel/cindel.dart`, but the browser needs everything `cindel_flutter_libs` ships.

```yaml theme={null}
dependencies:
  cindel: ^1.0.0
  cindel_flutter_libs: ^1.0.0  # bundles the Web worker, JS glue, and Wasm runtime
dev_dependencies:
  build_runner: ^2.15.0
  cindel_generator: ^1.0.0
```

## Browser Requirements

Cindel Web requires the following browser features to be available:

* **Workers** — used to run the database engine off the main thread
* **Wasm** — the native Rust core is compiled to WebAssembly
* **OPFS** — the Origin Private File System is where Cindel stores database files

All modern browsers support these features. If the browser, a privacy mode, or an embedded WebView blocks any of them, opening the database can fail. See [Handling Storage Errors](#handling-storage-errors) below.

<Note>
  MDBX is not used in browsers. Do not configure MDBX as a backend for Web targets — use the default SQLite/OPFS path.
</Note>

## Opening a Web Database

Pass a logical name to `directory` when calling `Cindel.open`. This name identifies the browser database; it is not a folder that appears on the user's device.

```dart theme={null}
// On web, directory is a logical name (not a file path)
final db = await Cindel.open(
  directory: 'myapp_production',
  schemas: [TodoSchema],
);
```

Once open, use your generated collections exactly as you would on native:

```dart theme={null}
await db.todos.put(todo);

final saved = await db.todos.get(todo.dbId);
final all   = await db.todos.all().findAll();
```

### In-Memory Databases for Tests

For unit tests or temporary work that should not persist between runs, use `Cindel.openInMemory`:

```dart theme={null}
final db = await Cindel.openInMemory(schemas: [TodoSchema]);
```

<Note>
  Use stable, descriptive `directory` names for your production database (e.g. `myapp_production`) and separate names for demos, previews, or tests (e.g. `myapp_demo`, `myapp_test`) so they never share browser storage.
</Note>

## Supported APIs on Web

All of the following work the same on Web as they do on native:

| Feature                                            | Supported |
| -------------------------------------------------- | --------- |
| `Cindel.open`                                      | ✅         |
| `Cindel.openInMemory`                              | ✅         |
| Typed CRUD (`put`, `get`, `delete`, etc.)          | ✅         |
| Typed queries                                      | ✅         |
| Property projections and aggregates                | ✅         |
| Query updates and deletes                          | ✅         |
| Read and write transactions                        | ✅         |
| `documentIdsPage` bounded scans                    | ✅         |
| Uncompressed JSONL backup import/export            | ✅         |
| Sync config via `CindelSyncConfig`                 | ✅         |
| Typed object, collection, query, and lazy watchers | ✅         |

### Example: Query with Sorting

```dart theme={null}
final newest = await db.todos
    .all()
    .sortByCreatedAt(order: CindelSortOrder.descending)
    .limit(20)
    .findAll();
```

### Example: Collection Watcher

```dart theme={null}
final sub = db.todos.watchCollection().listen((todos) {
  // Update your Web UI state here.
});
```

## Backup on Web

Use `CindelBackupCompression.none` when exporting on Web. Gzip compression is not supported in the browser runtime.

```dart theme={null}
await CindelBackup.exportDatabase(
  database: db,
  collections: [CindelBackupCollection(TodoSchema)],
  compression: CindelBackupCompression.none,
  output: output,
);
```

## Current Limitations

Keep the following restrictions in mind when targeting Web:

* **No MDBX backend** — only SQLite/OPFS is available in browsers.
* **Watcher delivery is single-tab only** — this includes sync watchers. One tab cannot receive watcher events triggered by writes in another tab.
* **No multi-tab coordination** — if your app supports multiple tabs, design the UI so each tab can reload or re-open its local view independently.
* **Browser storage quota and OPFS availability vary** — quota limits and OPFS support depend on the browser, OS, and user settings.

## Handling Storage Errors

If the browser blocks Workers, Wasm, or OPFS — for example in a private browsing session or when storage quota is exceeded — `Cindel.open` will throw a `CindelOpenError`.

<Warning>
  Always wrap `Cindel.open` in a try/catch on Web and show a clear in-app message when storage is unavailable. Do not assume OPFS is available in all browsing contexts — private mode and certain mobile WebViews are common failure points.
</Warning>

```dart theme={null}
try {
  final db = await Cindel.open(
    directory: 'myapp_production',
    schemas: [TodoSchema],
  );
} on CindelOpenError catch (e) {
  // Storage unavailable — show a user-facing message.
  showStorageUnavailableDialog(e);
}
```
