By default, this allows you to interact with Firestore using the default Firebase App used whilst installing FlutterFire on your
platform. If however you'd like to use Firestore with a secondary Firebase App, use the instanceFor method:
Firestore stores data within "documents", which are contained within "collections". Documents can also contain
nested collections. For example, our users would each have their own "document" stored inside the "Users" collection.
The collection method allows us to reference a collection within our code.
In the below example, we can reference the collection users, and create a new user document when a button is pressed:
// Import the firebase_core and cloud_firestore plugin
FlutterFire provides support for dealing with realtime changes to collections and documents. A new event is provided
on the initial request, and any subsequent changes to collection/document whenever a change occurs (modification, deleted
Once returned, you can subscribe to updates via the listen() method. The below example uses a StreamBuilder
which helps automatically manage the streams state and disposal of the stream when it's no longer used within your app:
By default, listeners do not update if there is a change that only affects the metadata. If you want to receive events
when the document or query metadata changes, you can pass includeMetadataChanges to the snapshots method:
A QuerySnapshot is returned from a collection query, and allows you to inspect the collection, such as how many documents
exist within it, gives access to the documents within the collection, see any changes since the last query and more.
A DocumentSnapshot also provides the ability to access
deeply nested data without manually iterating the returned Map via the get
method. The method accepts a dot-separated path or a FieldPath instance.
If no data exists at the nested path, a StateError:
To filter documents within a collection, the where method can be chained
onto a collection reference. Filtering supports equality checks and "in" queries. For example, for filter
users where their age is greater than 20:
.where('age', isGreaterThan: 20)
Firestore also supports array queries. For example, to filter users who speak English (en) or Italian (it), use
the arrayContainsAny filter:
To start and/or end a query at a specific point within a collection, you can pass a value to the startAt, endAt,
startAfter or endBefore methods. You must specify an order to use cursor queries, for example:
.startAt([4, 'Alphabet Inc.'])
.endAt([21, 'Google LLC'])
You can further specify a DocumentSnapshot instead of a specific value,
by passing it to the startAfterDocument, startAtDocument, endAtDocument or endBeforeDocument methods. For example:
Cloud Firestore does not support the following types of queries:
Queries with range filters on different fields, as described in the previous section.
Logical OR queries. In this case, you should create a separate query for each OR condition and merge the query results
in your app.
Queries with a != clause. In this cause, you should split the query into a greater-than query and a less-than query.
For example, the query clause where("age", isNotEqualTo: 30) is not supported, however you can get the same result set
by combining two queries, one with the clause where("age", isLessThan: 30) and one with the clause
where("age", isGreaterThan: 30)
Sometimes you may wish to update a document, rather than replacing all of the data. The set
method above replaces any existing data on a given DocumentReference.
If you'd like to update a document instead, use the update method:
Transactions are a way to ensure that a write operation only occurs using the latest data available on the server.
Transactions never partially apply writes, and writes execute at the end of a successful transaction.
Transactions are useful when you want to update a field based on its current value, or the value of another field. If
you want to write multiple documents without using the documents current state, a batch write
should be used.
When using transactions, note that:
Read operations must come before write operations
Transactions will fail when the client is offline, they cannot use cached data
An example of where a transaction could be used would be in an application where a user can subscribe to a channel. When
a user presses the subscribe button, a "subscribers" field in a document increments. Without using Transactions, we would
first need to read the existing value, and then increment that value using two separate operations.
On a high traffic application, the value on the server could have already changed by the time the write operation sets
a new value, causing the number to be inconsistent.
Transactions remove this issue by atomically updating the value of the server. If the value changes whilst the transaction
is executing, it will retry, ensuring the value on the server is used, rather than the client value.
.then((value) => print("Follower count updated to $value"))
.catchError((error) => print("Failed to update user followers: $error"));
In the above example, if the document changes at any point during the transaction, it will retry
up-to five times.
You should not directly modify application state inside of the transaction, as the handler may execute multiple
times. You should instead return a value at the end of the handler, updating application state once the transaction
If an exception is thrown within the handler, the entire transaction will be aborted.
Firestore lets you execute multiple write operations as a single batch that can contain any
combination of set, update,
or delete operations.
First, create a new batch instance via the batch method, then perform
the operations on the batch, and then commit it once ready. The below example shows how to delete
all documents in a collection in a single operation:
Firestore provides out of the box support for offline capabilities. When reading and writing data, Firestore uses a
local database which automatically synchronizes with the server. Cloud Firestore functionality continues when users are
offline, and automatically handles data migration when they regain connectivity.
This functionality is enabled by default, however it can be disabled if needed. The settings must be set before any Firestore interaction is performed:
Calls to update settings or clearing persistence must be carried out before any other usage of
Firestore. If called afterwards, they will take effect on the next Firestore claim (e.g. restarting
When persistence is enabled, Firestore caches every document for offline access. After exceeding the cache size, Firestore
will attempt to remove older, unused data. You can configure different cache sizes, or disable the removal process:
// The default value is 40 MB. The threshold must be set to at least 1 MB,
// and can be set to Settings.CACHE_SIZE_UNLIMITED to disable garbage collection.
It is possible to disable network access for your Firestore client. While network access is disabled, all Firestore requests
retrieve results from the cache. Any write operations are queued until network access is re-enabled.
If you are using the local Firestore emulators, then it is possible to
connect to these by passing a host parameter to the settings method,
immediately after initializing Firebase. Ensure you pass the correct port on which the Firebase emulator is running on.
Ensure you have enabled network connections to the emulators in your apps following the emulator usage instructions in the general FlutterFire installation notes for each operating system.
On Android emulators, to reference localhost, use the 10.0.2.2 IP address instead.