Skip to content

Firestore Indexes Guide: Composite, Collection Group & Query Performance

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Firestore Indexes Guide: Composite, Collection Group & Query Performance. We cover key concepts, practical examples, and best practices to help you master this topic.

Firestore uses indexes to deliver fast query results — every query matches an index, and understanding composite and collection group indexes is essential for query performance and cost control.

What You'll Learn

How Firestores indexing system works, when to create composite indexes, how collection group indexes enable cross-subcollection queries, and strategies to minimize index bloat.

Why It Matters

Unindexed queries fail with errors. Too many indexes increase write latency and storage costs. DodaTech's threat platform manages 50+ composite indexes across 10 collections to balance query speed with write performance.

Real-World Use

An enterprise threat dashboard needs fast filtered queries across millions of scan records. Proper indexing ensures sub-second response times for severity + date range filters with sort order.

flowchart LR
    A["Query with\nwhere + orderBy"] --> B["Index Lookup"]
    B --> C{"Index Exists?"}
    C -->|Yes| D["Scan Index\nO(log n)"]
    D --> E["Return\nDocuments"]
    C -->|No| F["Error:\nCreate Index"]
    F --> G["Firebase Console\nOne-click create"]
    G --> E
    style A fill:#dbeafe,stroke:#2563eb
    style D fill:#bbf7d0,stroke:#16a34a
    style F fill:#fecaca,stroke:#dc2626

Automatic Single-Field Indexes

Firestore automatically creates indexes for each field. Simple equality queries use these automatically:

// These queries use automatic single-field indexes —
// no manual index creation needed
const q1 = query(collection(db, "devices"), where("os", "==", "Windows"));
const q2 = query(collection(db, "scans"), orderBy("timestamp", "desc"));
const q3 = query(collection(db, "users"), where("email", "==", "alice@example.com"));

Creating Composite Indexes

Compound queries require composite indexes. The error message from a failed query includes a direct Console link:

// This query needs a composite index on [severity, timestamp desc]
async function getCriticalScansRecent() {
  const q = query(
    collection(db, "scans"),
    where("severity", "==", "critical"),
    orderBy("timestamp", "desc"),
    limit(20)
  );
  const snapshot = await getDocs(q);
  console.log("Critical scans:", snapshot.size);
}

Create the index via Firebase Console or CLI:

# Using Firebase CLI
firebase firestore:indexes

# Deploy indexes from firestore.indexes.json
firebase deploy --only firestore:indexes

Example firestore.indexes.json:

{
  "indexes": [
    {
      "collectionGroup": "scans",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "severity", "order": "ASCENDING" },
        { "fieldPath": "timestamp", "order": "DESCENDING" }
      ]
    }
  ]
}

Collection Group Indexes

For collection group queries across subcollections, create indexes with queryScope: "COLLECTION_GROUP":

{
  "indexes": [
    {
      "collectionGroup": "scans",
      "queryScope": "COLLECTION_GROUP",
      "fields": [
        { "fieldPath": "userId", "order": "ASCENDING" },
        { "fieldPath": "timestamp", "order": "DESCENDING" }
      ]
    }
  ]
}
// Uses the collection group index above
async function getAllUserScans(userId) {
  const q = query(
    collectionGroup(db, "scans"),
    where("userId", "==", userId),
    orderBy("timestamp", "desc")
  );
  const snapshot = await getDocs(q);
  console.log("Total scans across all devices:", snapshot.size);
}

Index Exemptions and Sparse Indexes

Some fields rarely need indexing. Disable automatic indexes for high-cardinality fields:

// In firestore.indexes.json, exempt fields from automatic indexing
{
  "fieldOverrides": [
    {
      "collectionGroup": "logs",
      "fieldPath": "rawPayload",
      "indexes": []
    }
  ]
}

This saves storage and improves write performance for fields you never query.

Monitoring Index Performance

// Firestore provides index usage metrics in the Console:
// - Index count by collection
// - Queries using each index
// - Write latency impact
// - Storage used by indexes

// Use the Firebase Console > Firestore > Indexes tab to:
// - View all indexes per collection
// - See which indexes are unused
// - Delete indexes that waste storage

Common Mistakes

1. Over-Indexing

Creating indexes for every field combination increases write latency and storage. Create indexes only for queries your app actually runs.

When a compound query fails, the error message includes a direct Console link. Click it to create the index in one click — no manual configuration needed.

3. Wrong Sort Direction in Index

Composite indexes must match the sort direction of your query. An ASC + DESC index is different from ASC + ASC. Index creation in the Console lets you specify each direction.

4. Not Using __name__ in Indexes

Firestore requires an index on __name__ for certain queries. The automatic index covers most cases, but queries with multiple range conditions need explicit attention.

5. Deleting Indexes Used by Active Queries

Removing an index that queries depend on causes those queries to fail. Always verify query patterns before deleting indexes.

Practice Questions

  1. How does Firestore use indexes for query execution?
  2. When do you need a composite index vs a single-field index?
  3. What is a collection group index and when do you use it?
  4. How do exempted fields improve performance?

Answers:

  1. Firestore reads the index in sorted order to find matching documents, then fetches those documents. This makes query time proportional to result size, not collection size.
  2. Simple equality queries on one field use single-field indexes. Compound queries with multiple where clauses or where + orderBy need composite indexes.
  3. Collection group indexes enable queries across all subcollections with the same name, used with collectionGroup() queries.
  4. Exempted fields skip indexing entirely, reducing storage and improving write speed for fields never used in queries.

Challenge: Audit the indexes for Durga Antivirus Pro's scans collection. Identify which queries need composite indexes, create them via firestore.indexes.json, and exempt the rawPayload field from automatic indexing.

FAQ

How many indexes can I create in Firestore?

Firestore supports up to 200 composite indexes per database. You can request quota increases through Google Cloud support.

Do indexes increase write costs?

Yes, each index update counts as a write operation. A document write on a collection with 5 indexes costs 6 writes (1 document + 5 index entries).

How long does index creation take?

Index creation takes minutes for small collections. For collections with millions of documents, it can take hours. Monitor progress in the Console.

Can I delete unused indexes?

Yes. The Console shows index usage statistics. Delete unused indexes to reduce storage costs and improve write performance.

What happens if I exceed the index limit?

New composite index creation fails. You must delete unused indexes or request a quota increase.

Mini Project

Design the index Strategy for a multi-tenant security app: identify 3 essential composite indexes for the most common queries, create them via the Console, configure a collection group index for cross-device queries, and exempt audit log payloads from indexing.

What's Next

Cloud Storage for Firebase — store and serve user-uploaded files securely.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro