What is the difference between existing types of snapshots in Firebase?

As far as I can tell you are asking this in the context of Flutter, so I'll answer for that below.

There are two databases in Firebase: the original Realtime Database, and the newer Cloud Firestore. Both are equally valid options today, but they are completely separate with their own API. But both return snapshots of data, where the snapshot is a copy of the data from the database in your application code.

In Flutter you have FutureBuilder and StreamBuilder, which deal with snapshots of data that is loaded asynchronously.

Let's see if I can cover them:

  • An AsyncSnapshot is Flutter's wrappers around data from asynchronous data sources, such as Firestore and Realtime Database. They cover the states that such data can be in, from the initial connection, through retrieval, until errors or having the data.
  • DocumentSnapshots and QuerySnapshots are Firestore's classes to either represent a single document, or a list of documents that you get when reading from the database. So if you load a single document, you get a DocumentSnapshot with its data. And if you load a list of document, you get a QuerySnapshot that you then loop over to access the individual DocumentSnapshots.
  • A DataSnapshot is the Realtime Database's class for both a single Node, and a list of nodes from the database.

So in Flutter you'll have an AsyncSnapshot that refers to one of the Firebase snapshot classes, and that Firebase snapshot then wraps the actual data.


Say you want to display a list with the documents in a collection from Firestore, you'll have:

  1. An AsyncSnapshot to feed to your StreamBuilder, so that it can render the correct state of data loading.
  2. A QuerySnapshot for the list of documents from the database.
  3. Each item in that list is then a DocumentSnapshot with a snapshot of the data from a single document.

I actually find this much easier to see in code, as in this example from the FlutterFire documentation:

class UserInformation extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    CollectionReference users = FirebaseFirestore.instance.collection('users');

    return StreamBuilder<QuerySnapshot>(
      stream: users.snapshots(),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (snapshot.hasError) {
          return Text('Something went wrong');
        }

        if (snapshot.connectionState == ConnectionState.waiting) {
          return Text("Loading");
        }

        return new ListView(
          children: snapshot.data.documents.map((DocumentSnapshot document) {
            return new ListTile(
              title: new Text(document.data()['full_name']),
              subtitle: new Text(document.data()['company']),
            );
          }).toList(),
        );
      },
    );
  }
}