Skip to main content
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:
user.dart
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. 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.
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.

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

Quickstart

Follow the step-by-step guide to define a model, generate code, and run your first typed query in a Flutter app.