> ## 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: Flutter-First Local Database — Full Overview

> Learn what Cindel is, how its code-generation model works, and which storage backend to choose for native, mobile, and web Flutter apps.

Cindel is a local-first, embedded database for Flutter and Dart applications. It stores structured data on-device through a Rust native core, exposes the database through a generated typed Dart API, and runs on every platform that Flutter targets — Android, iOS, macOS, Linux, Windows, and Web. Your application never touches raw rows or stringly typed maps; it works exclusively with Dart objects through a generated surface that is checked at compile time.

## What Cindel is

Cindel is not a remote backend or a sync service. It is an embedded database that lives inside your app and makes local structured data available quickly and with full Dart type safety.

It is useful when your app needs:

* offline-capable structured data that survives app restarts,
* cached records that are still queryable without a network connection,
* local-first workflows where writes happen on-device before being synced,
* durable UI state such as task lists, product catalogs, settings, or message threads.

Cindel is designed to complement your server, not replace it. If you need sync, you still provide the backend and a thin adapter; Cindel handles local storage, records local mutations in a durable outbox, and calls your adapter through a defined contract.

## The code-generation model

Cindel's public API is entirely generated. The workflow is:

1. **Annotate a class.** Add `@Collection()` (or `@collection`) to a Dart class, declare an `Id dbId = autoIncrement` field, and mark indexed fields with `@Index`.
2. **Add a `part` directive.** Include `part 'modelname.g.dart';` in the model file so the generator can attach the output.
3. **Run `build_runner`.** Execute `dart run build_runner build` to produce the schema constant, typed collection getter, serializers, and query helpers.
4. **Use the generated API.** Register the generated schema when you open the database, then read and write through the typed collection getter.

A minimal model looks like this:

```dart user.dart theme={null}
import 'package:cindel_annotations/cindel_annotations.dart';

part 'user.g.dart';

@Collection(name: 'users')
class User {
  Id dbId = autoIncrement;

  @Index(unique: true)
  late String email;

  @Index()
  late String name;

  bool active = true;
}
```

After generation, the app registers `UserSchema` and uses `db.users`. Every method on `db.users` is typed to `User`:

* `db.users.put(user)` accepts a `User`.
* `db.users.get(id)` returns a `Future<User?>`.
* Query helpers such as `db.users.filter().activeEqualTo(true).findAll()` are generated from your model's field names.
* Invalid field names cannot be passed as plain strings in everyday app code.

## Available backends

Cindel selects its storage backend at open time. The application-level API stays the same regardless of which backend is active.

| Backend           | Platforms                           | How to select                               |
| ----------------- | ----------------------------------- | ------------------------------------------- |
| MDBX (default)    | Android, iOS, macOS, Linux, Windows | Omit the `backend` parameter                |
| SQLite native     | Android, iOS, macOS, Linux, Windows | Pass `backend: CindelStorageBackend.sqlite` |
| SQLite Web / OPFS | Browser (Flutter Web)               | Automatic — MDBX is not used in browsers    |

Use MDBX for new native apps unless you have a specific reason to prefer SQLite. Both backends expose the same schemas, collection getters, queries, transactions, and watchers — switching backends does not require rewriting application code.

On the web, `cindel_flutter_libs` bundles the SQLite Worker and Wasm assets. The `directory` parameter in `Cindel.open` becomes a logical browser database name rather than a filesystem path.

## Core query entry points

Every generated collection exposes three query starting points:

* **`all()`** — starts from the entire collection with no filter.
* **`where()`** — uses generated helpers for fields marked with `@Index`; ideal for high-performance indexed lookups.
* **`filter()`** — uses generated helpers for any stored field; supports rich predicates, string matching, list element queries, and boolean composition.

```dart theme={null}
// Full collection scan
final everyone = await db.users.all().findAll();

// Indexed lookup — fast path through the index
final ada = await db.users
    .where()
    .emailEqualTo('ada@example.com')
    .findFirst();

// Field filter — works on any stored field
final activeUsers = await db.users
    .filter()
    .activeEqualTo(true)
    .findAll();
```

Both `where()` and `filter()` chains support sorting, pagination, distinct values, projections, aggregates, query-scoped updates, and query-scoped deletes. Watchers can be attached to any query chain.

## Reactive watchers

Cindel can emit a fresh typed snapshot every time matching data changes. You attach a watcher to an object, a collection, or a query chain, and your stream listener receives the updated result without polling.

```dart theme={null}
// Watch the whole collection
db.users.watchCollection().listen((users) {
  // Rebuild your widget with the latest snapshot.
});

// Watch a filtered query
db.users
    .filter()
    .activeEqualTo(true)
    .sortByName()
    .watch()
    .listen((activeUsers) {
      // Only fires when the active-user set changes.
    });
```

## When to use Cindel vs. a remote database

Use Cindel when your app needs fast, typed, queryable data that lives on the device — task lists, product catalogs, draft content, user preferences, or anything that should work offline.

Use a remote database (or add Cindel's experimental sync) when authoritative data must be shared across devices or users, or when the server is the system of record.

The two approaches are complementary: many apps store a local Cindel database for offline performance and sync changes to a backend when connectivity is available.

## Next steps

<Card title="Quickstart" icon="rocket" href="/quickstart">
  Follow the step-by-step guide to define a model, generate code, and run your first typed query in a Flutter app.
</Card>
