How to fix Firestore: Read operations must be executed before write operations in Firebase

FirebaseINTERMEDIATEMEDIUMUpdated Dec 22, 2025· 145 views

This error occurs when you attempt to read a document after performing a write operation within a Firestore transaction, violating the fundamental constraint that all reads must happen before any writes.

Quick fix

Fixes Firestore: Read operations must be executed before write operations

// ❌ WRONG: Read after write
await db.runTransaction(async (transaction) => {
  const docRef = db.collection('users').doc('alice');

  // Write first
  transaction.update(docRef, { credits: 100 });

  // Read after - THIS WILL FAIL
  const doc = await transaction.get(docRef);
  const balance = doc.data().balance;
});

// ✅ CORRECT: Read before write
await db.runTransaction(async (transaction) => {
  const docRef = db.collection('users').doc('alice');

  // Read first
  const doc = await transaction.get(docRef);
  const balance = doc.data().balance;

  // Then write
  transaction.update(docRef, { credits: balance + 100 });
});
  1. Move all read operations before write operations
  2. Gather all data needed before writing
  3. Use batched writes if you don't need to read
  4. Verify async/await ordering
firebase — error
// ❌ WRONG: Read after write
await db.runTransaction(async (transaction) => {
const docRef = db.collection('users').doc('alice');
// Write first
transaction.update(docRef, { credits: 100 });
// Read after - THIS WILL FAIL
const doc = await transaction.get(docRef);
const balance = doc.data().balance;
});
// ✅ CORRECT: Read before write
await db.runTransaction(async (transaction) => {
const docRef = db.collection('users').doc('alice');
// Read first
const doc = await transaction.get(docRef);
const balance = doc.data().balance;
// Then write
transaction.update(docRef, { credits: balance + 100 });
});
Firestore: Read operations must be executed before write operations

What this error means

This error is thrown when you violate Firestore's transaction ordering rule: all read operations must be executed before any write operations within a transaction. Firestore enforces this constraint to ensure data consistency and enable its automatic retry mechanism. When a transaction runs, Firestore needs to validate that all documents you read haven't been modified by concurrent operations before committing your writes. By requiring reads first, Firestore can detect conflicts and automatically retry the transaction with fresh data if needed. All writes execute atomically at the end of a successful transaction, never partially applying changes. This design ensures that transactions run on up-to-date and consistent data. If you attempt to call get() or getDocument() after set(), update(), or delete() operations in your transaction function, Firestore immediately throws this error to prevent inconsistent state.

Typical symptoms

  • Error message: "Firestore transactions require all reads to be executed before all writes"
  • Transaction fails when trying to read a document after updating or creating another document
  • Code with get() calls after set(), update(), or delete() operations throws an error
  • Transaction function that conditionally reads based on write results fails immediately

Common causes

  1. Calling transaction.get() or transaction.getDocument() after transaction.set(), transaction.update(), or transaction.delete()
  2. Reading a document conditionally based on the result of a write operation within the same transaction
  3. Incorrect ordering of operations when refactoring transaction code
  4. Using async/await incorrectly, causing reads to execute after writes despite appearing first in code
  5. Attempting to read a document to verify a write operation within the same transaction

How to fix "Firestore: Read operations must be executed before write operations"

1Move all read operations before write operations

Restructure your transaction so all get() calls happen first:

javascript
// ❌ WRONG: Read after write
await db.runTransaction(async (transaction) => {
  const docRef = db.collection('users').doc('alice');

  // Write first
  transaction.update(docRef, { credits: 100 });

  // Read after - THIS WILL FAIL
  const doc = await transaction.get(docRef);
  const balance = doc.data().balance;
});

// ✅ CORRECT: Read before write
await db.runTransaction(async (transaction) => {
  const docRef = db.collection('users').doc('alice');

  // Read first
  const doc = await transaction.get(docRef);
  const balance = doc.data().balance;

  // Then write
  transaction.update(docRef, { credits: balance + 100 });
});

Perform all document reads at the beginning of your transaction function, then perform all writes afterward.

2Gather all data needed before writing

If your writes depend on multiple documents, read all of them upfront:

javascript
await db.runTransaction(async (transaction) => {
  // Read all documents first
  const userRef = db.collection('users').doc('alice');
  const accountRef = db.collection('accounts').doc('12345');
  const settingsRef = db.collection('settings').doc('global');

  const [userDoc, accountDoc, settingsDoc] = await Promise.all([
    transaction.get(userRef),
    transaction.get(accountRef),
    transaction.get(settingsRef)
  ]);

  // Extract all data you need
  const userData = userDoc.data();
  const accountData = accountDoc.data();
  const maxTransfer = settingsDoc.data().maxTransferAmount;

  // Now perform all writes based on the read data
  if (userData.balance >= 100 && accountData.balance + 100 <= maxTransfer) {
    transaction.update(userRef, { balance: userData.balance - 100 });
    transaction.update(accountRef, { balance: accountData.balance + 100 });
  }
});
3Use batched writes if you don't need to read

If your operation doesn't require reading documents, use a batch instead of a transaction:

javascript
// Batched writes don't have the read-before-write restriction
const batch = db.batch();

const userRef = db.collection('users').doc('alice');
const logRef = db.collection('logs').doc();

batch.update(userRef, { lastLogin: new Date() });
batch.set(logRef, {
  user: 'alice',
  action: 'login',
  timestamp: new Date()
});

await batch.commit();

Batched writes execute atomically and can write to multiple documents without any read constraints. Use this when you only need to write data.

4Verify async/await ordering

Ensure you're using async/await correctly so operations execute in the intended order:

javascript
// ❌ WRONG: Missing await causes race condition
await db.runTransaction(async (transaction) => {
  const docRef = db.collection('items').doc('item1');

  // This write might execute before the read below
  transaction.set(db.collection('logs').doc(), { action: 'update' });

  // Missing await here
  transaction.get(docRef).then(doc => {
    // This read happens after the write!
    const data = doc.data();
  });
});

// ✅ CORRECT: Proper await ensures ordering
await db.runTransaction(async (transaction) => {
  const docRef = db.collection('items').doc('item1');

  // Read with await
  const doc = await transaction.get(docRef);
  const data = doc.data();

  // Then write
  transaction.set(db.collection('logs').doc(), {
    action: 'update',
    previousValue: data.value
  });
});

Always use await on transaction.get() calls to ensure they complete before subsequent operations.

Advanced notes

Transaction Retry Mechanism: Firestore automatically retries transactions when documents you've read are modified by concurrent operations. This is why reads must come first—the system needs to detect conflicts before applying writes. If a retry occurs, your entire transaction function runs again with fresh data.

Performance Consideration: Reading many documents in a transaction can increase the likelihood of conflicts and retries, especially in high-traffic applications. If you're experiencing frequent transaction failures due to contention, consider restructuring your data model or using batched writes when possible.

Read-Only Transactions: Some Firestore SDKs support read-only transaction modes that can improve performance for operations that only read data. These don't have the ordering restriction since they never write.

Two-Phase Operations: If you must read after a write (e.g., to verify the result), split the operation into two separate transactions or use a write followed by a separate read outside the transaction. Remember that Firestore's atomic commits ensure your transaction writes succeed completely or not at all.

Frequently asked questions

What does "Firestore: Read operations must be executed before write operations" mean?
This error is thrown when you violate Firestore's transaction ordering rule: all read operations must be executed before any write operations within a transaction. Firestore enforces this constraint to ensure data consistency and enable its automatic retry mechanism. When a transaction runs, Firestore needs to validate that all documents you read haven't been modified by concurrent operations before committing your writes.
How do I fix "Firestore: Read operations must be executed before write operations"?
This error occurs when you attempt to read a document after performing a write operation within a Firestore transaction, violating the fundamental constraint that all reads must happen before any writes.
What causes "Firestore: Read operations must be executed before write operations"?
Calling transaction.get() or transaction.getDocument() after transaction.set(), transaction.update(), or transaction.delete() Reading a document conditionally based on the result of a write operation within the same transaction Incorrect ordering of operations when refactoring transaction code
Is the "Firestore: Read operations must be executed before write operations" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading