Firestore Batch Writes

A batch write groups multiple create, update, and delete operations into a single request. All operations in the batch either succeed together or fail together. Batches are faster than individual writes because they make one network round trip instead of many.

Batch vs Transaction

Batches and transactions both group operations atomically, but they serve different purposes:

Batch Write:
- Write-only (no reads inside the batch)
- Does not retry on conflicts
- Faster — just sends the writes and commits
- Best for: creating multiple documents at once,
  seeding data, mass updates

Transaction:
- Reads and writes allowed
- Retries if conflicting changes detected
- Slower — reads first, then writes, then checks
- Best for: operations where writes depend
  on current values (e.g., decrement stock)

Creating a Batch

import { writeBatch, doc, collection } from "firebase/firestore";
import { db } from "./firebase";

const batch = writeBatch(db);

The batch object collects operations. Nothing runs until you call batch.commit().

Adding Operations to a Batch

// Create new documents
const post1Ref = doc(collection(db, "posts"));
batch.set(post1Ref, {
  title: "Introduction to Firebase",
  authorId: "uid_alice",
  status: "published"
});

const post2Ref = doc(collection(db, "posts"));
batch.set(post2Ref, {
  title: "Firestore in 10 Minutes",
  authorId: "uid_alice",
  status: "draft"
});

// Update an existing document
const userRef = doc(db, "users", "uid_alice");
batch.update(userRef, { postCount: 2 });

// Delete a document
const oldPostRef = doc(db, "posts", "old_post_001");
batch.delete(oldPostRef);

// Commit all operations at once
await batch.commit();
console.log("All batch operations completed.");

Batch Limits

A single batch supports a maximum of 500 operations. Each set, update, or delete counts as one operation. If you need more than 500 operations, split them across multiple batches.

// Splitting a large batch
async function batchDeletePosts(postIds) {
  const BATCH_SIZE = 500;

  for (let i = 0; i < postIds.length; i += BATCH_SIZE) {
    const batch = writeBatch(db);
    const chunk = postIds.slice(i, i + BATCH_SIZE);

    chunk.forEach((id) => {
      batch.delete(doc(db, "posts", id));
    });

    await batch.commit();
    console.log(`Deleted batch ${i / BATCH_SIZE + 1}`);
  }
}

Practical Example: User Registration with Profile

When a new user signs up, you often want to create multiple documents simultaneously — the user profile, initial settings, and a welcome notification. A batch handles all of these in one operation:

async function setupNewUser(uid, email, displayName) {
  const batch = writeBatch(db);

  // Create user profile
  batch.set(doc(db, "users", uid), {
    displayName,
    email,
    createdAt: new Date(),
    plan: "free"
  });

  // Create default settings
  batch.set(doc(db, "settings", uid), {
    theme: "light",
    notifications: true,
    language: "en"
  });

  // Create welcome notification
  const notifRef = doc(collection(db, "users", uid, "notifications"));
  batch.set(notifRef, {
    message: "Welcome to the app, " + displayName + "!",
    read: false,
    createdAt: new Date()
  });

  await batch.commit();
  console.log("New user setup complete.");
}

Mass Update Example

Updating many documents to reflect a price change or category rename:

async function updateCategory(oldCategory, newCategory) {
  // First, find all affected documents
  const q = query(
    collection(db, "products"),
    where("category", "==", oldCategory)
  );
  const snapshot = await getDocs(q);

  // Process in batches of 500
  const docs = snapshot.docs;
  for (let i = 0; i < docs.length; i += 500) {
    const batch = writeBatch(db);
    docs.slice(i, i + 500).forEach((d) => {
      batch.update(d.ref, { category: newCategory });
    });
    await batch.commit();
  }

  console.log(`Updated ${docs.length} products.`);
}

Key Takeaway

Batch writes group up to 500 Firestore write operations into a single atomic request. Use batches when you need to create, update, or delete multiple documents at once without reading any values inside the batch. Batches are faster and simpler than transactions for write-only operations. For large datasets exceeding 500 documents, split operations across multiple consecutive batches.

Leave a Comment

Your email address will not be published. Required fields are marked *