Type-safe Firestore ODM for Flutter and Dart — the maintained successor to cloud_firestore_odm.
Documentation · Getting started · Migrate from cloud_firestore_odm · Benchmarks
Describe your documents once. firestore_odm generates typed queries, updates, aggregates, transactions and streams for them, so a misspelled field or a wrong value type is a compile error instead of a production bug.
@firestoreOdm
class User {
const User({required this.id, required this.name, required this.age, this.tags = const [], this.lastLogin});
@DocumentIdField()
final String id;
final String name;
final int age;
final List<String> tags;
final DateTime? lastLogin;
}
class AppSchema extends FirestoreSchema {
const AppSchema();
}
@Schema()
@Collection<User>('users')
@Collection<Post>('users/*/posts') // Post: another @firestoreOdm model
const appSchema = AppSchema();final db = FirestoreODM(appSchema);
// Typed filters, ordering and paging. Returns List<User>.
final adults = await db.users
.where(($) => $.age(isGreaterThanOrEqualTo: 18) & $.tags(arrayContains: 'beta'))
.orderBy(($) => ($.age(descending: true), $.name()))
.limit(20)
.get();
// Typed atomic updates, including nested fields.
await db.users('kim').patch(($) => [
$.age.increment(1),
$.tags.arrayUnion(['admin']),
$.lastLogin.serverTimestamp(),
]);
// Server-side aggregates as a typed record.
final stats = await db.users
.aggregate(($) => (count: $.count(), averageAge: $.age.average()))
.get();
// Subcollections, streams and transactions.
db.usersPosts('kim').stream.listen((posts) => print(posts.length));
await db.runTransaction((tx) async {
final users = db.users.inTransaction(tx);
final kim = await users('kim').get();
users('kim').patch(($) => [$.age.set(kim!.age + 1)]);
});A complete, tested version of this example is in
example/lib/main.dart.
The official cloud_firestore_odm has not had a release since
1.0.0-dev.88 (October 2024). It requires cloud_firestore ^5, and its
generator requires analyzer <7, so it cannot be used with cloud_firestore
6, firebase_core 4, freezed 3 or a current json_serializable.
firestore_odm runs on current Firebase and Flutter, is released as stable versions, and goes further:
- Typed everything: filters (with
&and|), nested fields ($.profile.followers), ordering with record-typed cursors, partial updates, aggregates, transactions and batches. - Firestore semantics, no surprises:
DateTimeis stored as a native Timestamp;GeoPoint,DocumentReferenceandBlobfields are stored natively; every write maps to one Firestore call. - Any model style: plain Dart classes, freezed or json_serializable. The builder generates the Firestore converters, so json_serializable is optional. Fields added later with a default read fine from older documents.
- Bulk writes:
patchAllanddeleteAllover a query, chunked to Firestore's 500-write batch limit. - Fast builds: after a model edit, 20 models rebuild in 1.5 seconds,
against 17 seconds with cloud_firestore_odm; runtime cost stays within a few
microseconds of raw
cloud_firestore(benchmarks). - Firestore Pipelines (Enterprise edition, experimental) with typed stages.
flutter pub add firestore_odm cloud_firestore firebase_core
flutter pub add dev:firestore_odm_builder dev:build_runner
dart run build_runner build --delete-conflicting-outputsRequires Dart 3.8 or later and cloud_firestore 6. Supported on Android, iOS,
macOS, Windows and web (the platforms cloud_firestore supports).
| firestore_odm | cloud_firestore_odm | raw cloud_firestore | |
|---|---|---|---|
| Works with cloud_firestore 6 / firebase_core 4 | yes | no | yes |
| Typed filters and ordering | yes | yes | no (field names as strings) |
| OR filters and nested fields | yes | no | untyped |
| Typed partial updates (increment, arrayUnion, serverTimestamp) | yes | through untyped FieldValue |
no |
| Aggregates (count, sum, average) | typed | no | untyped |
| Typed transactions and batches | yes | update only | no |
| Update or delete every match of a query | yes | no | by hand |
| json_serializable required | no | yes | no |
| Last release | 2026, stable | 2024, pre-release | current |
The full comparison covers every feature and the other Firestore packages on pub.dev.
A codemod rewrites your pubspec, collection declarations, whereX / orderByX
queries, update(...) calls and subcollection access, and lists anything left
to finish by hand with file and line:
dart pub global activate firestore_odm_builder
dart pub global run firestore_odm_builder:migrate # preview
dart pub global run firestore_odm_builder:migrate --apply # writeYour Firestore data stays as it is. The migration guide maps every API.
- Getting started
- Schema and models
- Queries and pagination
- Writing documents
- Transactions and batches
- Aggregations
- API reference
Issues and pull requests are welcome. See
CONTRIBUTING.md
for the setup; melos run check runs what CI runs on a pull request.
- anymd: any file to clean Markdown for AI agents (PDF, Office, EPUB, web pages, images, audio, video); a Rust MCP server and CLI that runs locally.
- repomap: a map of your codebase for AI agents: code graph, search, call paths and change impact.
- lockdocs: exact-version library docs from your lockfile, local and offline.
- readme-mark: README banners, badges and stats cards from one URL (the banner above).