0
0
FirebaseHow-ToBeginner · 3 min read

How to Use Cursor Pagination in Firestore for Efficient Data Loading

Use Firestore's startAfter() or startAt() methods combined with limit() to paginate query results. Fetch the first page with a limit, then use the last document snapshot as a cursor for the next page to continue loading data efficiently.
📐

Syntax

Cursor pagination in Firestore uses query cursors like startAfter() or startAt() to mark where the next page of results begins. You combine these with limit() to control how many documents to fetch per page.

  • collectionRef.limit(n): Limits the number of documents to n.
  • startAfter(documentSnapshot): Starts the query after the given document snapshot.
  • startAt(documentSnapshot): Starts the query at the given document snapshot (inclusive).
javascript
const firstPageQuery = collectionRef.orderBy('field').limit(10);
const nextPageQuery = collectionRef.orderBy('field').startAfter(lastDoc).limit(10);
💻

Example

This example shows how to load the first 5 documents from a Firestore collection ordered by a field, then load the next 5 documents using cursor pagination.

javascript
import { getFirestore, collection, query, orderBy, limit, startAfter, getDocs } from 'firebase/firestore';

const db = getFirestore();
const colRef = collection(db, 'items');

async function loadFirstPage() {
  const firstQuery = query(colRef, orderBy('name'), limit(5));
  const firstSnapshot = await getDocs(firstQuery);
  firstSnapshot.docs.forEach(doc => console.log(doc.id, doc.data()));
  return firstSnapshot.docs[firstSnapshot.docs.length - 1];
}

async function loadNextPage(lastDoc) {
  const nextQuery = query(colRef, orderBy('name'), startAfter(lastDoc), limit(5));
  const nextSnapshot = await getDocs(nextQuery);
  nextSnapshot.docs.forEach(doc => console.log(doc.id, doc.data()));
  return nextSnapshot.docs[nextSnapshot.docs.length - 1];
}

(async () => {
  const lastDoc = await loadFirstPage();
  if (lastDoc) {
    await loadNextPage(lastDoc);
  }
})();
Output
Logs first 5 documents ordered by 'name', then logs next 5 documents after the last one from first page.
⚠️

Common Pitfalls

Common mistakes when using cursor pagination in Firestore include:

  • Not ordering the query by the same field used in the cursor, which causes errors.
  • Using startAfter() without a valid document snapshot as cursor.
  • Not handling the case when there are no more documents to paginate.
  • Mixing startAt() and startAfter() incorrectly, leading to duplicate or skipped results.
javascript
/* Wrong: Missing orderBy causes error */
const wrongQuery = query(colRef, startAfter(lastDoc), limit(5));

/* Right: Always include orderBy on the same field */
const rightQuery = query(colRef, orderBy('name'), startAfter(lastDoc), limit(5));
📊

Quick Reference

MethodPurposeNotes
limit(n)Limits results to n documentsUse to set page size
orderBy(field)Sorts documents by fieldRequired for cursor pagination
startAfter(doc)Starts query after given documentUse last doc snapshot from previous page
startAt(doc)Starts query at given document (inclusive)Includes the document in results

Key Takeaways

Always use orderBy with cursor methods for consistent pagination.
Use limit to control how many documents load per page.
Pass the last document snapshot from the previous page to startAfter for the next page.
Handle empty results to know when pagination ends.
Avoid mixing startAt and startAfter incorrectly to prevent duplicates.