Firestore Batch Writes — Complete Guide
In this tutorial, you'll learn about Firestore Batch Writes. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
You write 600 documents in a loop (over the 500-batch limit), or one write fails but the others succeed — leaving your data in an inconsistent state.
Wrong Approach ❌
// Writing 600 documents one by one — slow and not atomic
for (i in 0 until 600) {
db.collection("items").document("item$i")
.set(Item("Item $i", i))
.await() // 600 separate network writes!
}
Output: 600 network calls. If call 300 fails, first 299 are committed.
Right Approach ✅
class BatchRepository(private val db: FirebaseFirestore) {
// Atomic batch write — max 500 operations
suspend fun createItems(items: List<Item>) {
val batches = items.chunked(499) // 499 to leave room for deletes
batches.forEach { chunk ->
val batch = db.batch()
chunk.forEach { item ->
val docRef = db.collection("items").document()
batch.set(docRef, item)
}
// Also can include deletes and updates
batch.delete(db.collection("temp").document("staging"))
batch.update(db.collection("config").document("settings"), "lastBatch", System.currentTimeMillis())
batch.commit().await() // Atomic commit
}
}
// Batch update multiple fields across documents
suspend fun updateScores(scores: Map<String, Long>) {
val batch = db.batch()
scores.entries.chunked(499).forEach { chunk ->
val b = db.batch()
chunk.forEach { (userId, score) ->
val docRef = db.collection("users").document(userId)
b.update(docRef, "score", FieldValue.increment(score))
}
b.commit().await()
}
}
// Run both batch operations with WriteBatch
suspend fun complexBatchWrite() {
// A WriteBatch can contain set, update, and delete operations
val batch = db.batch()
// Set a new document
val newDoc = db.collection("orders").document()
batch.set(newDoc, Order("pending", userId))
// Update existing
val userDoc = db.collection("users").document(userId)
batch.update(userDoc, "orderCount", FieldValue.increment(1))
// Delete old temp data
val tempDoc = db.collection("temp").document("order_$userId")
batch.delete(tempDoc)
batch.commit().await()
}
}
Output: Atomic batch writes with no partially-committed data.
Prevention
- Max 500 operations per batch. Chunk larger batches.
- Batch operations are atomic — all succeed or all fail.
- Use
batch()for related writes that must be consistent. - Batches count as a single write operation for billing (each document still counts individually).
Common Mistakes with firestore batch
- Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
- Using
returnto exit a function early instead of wrapping a pure value in the monad - Mixing let bindings with <- bindings in do notation, producing type errors
These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro