Firestore rejects any write that would make a document larger than 1 MiB (1,048,576 bytes). That limit counts every field name, nested map/array, and binary/text value in the document. The fix is to split the payload into multiple documents/subcollections or move large blobs outside Firestore before writing.
Firestore enforces a hard 1 MiB limit on each document payload. Every byte of the serialized document—field names, values, nested maps/arrays, and even indexed fields—is counted toward the limit. Field values themselves are capped at 1 MiB minus 89 bytes, and verbose field names, deep maps, or many default index entries can push you over the threshold without adding much visible data. When the cap is exceeded, Firestore stops the write and returns the "Document exceeds 1 MiB maximum size" error to protect the distributed datastore.
Serialize the payload and count the UTF-8 bytes so you can stop short of Firestore's 1 MiB limit:
const payload = { /* your document */ };
const bytes = new TextEncoder().encode(JSON.stringify(payload)).length;
console.log(`Preparing to write ${bytes} bytes (limit: 1,048,576)`);
if (bytes >= 1_048_576) {
throw new Error('Document is too large; break it into smaller pieces first.');
}TextEncoder counts the same UTF-8 bytes that Firestore uses and includes field names plus Maps/arrays. Run this before every bulk write or inside Cloud Functions so you can log which document boundary is about to break the limit and avoid the failed write altogether.
Keep the root document lean by storing heavy arrays or maps in dedicated child documents:
const batch = db.batch();
batch.set(db.doc('offers/offerA'), { id: 'offerA', summary: '...', lastUpdated: Date.now() });
items.forEach((item, index) => {
const ref = db.collection('offers/offerA/items').doc(String(index));
batch.set(ref, item);
});
await batch.commit();Subcollections (e.g. offers/offerA/items) do NOT count toward the parent document's 1 MiB limit. Use pagination or chunked keys when writing dozens of children so each child document stays small. Store only a lightweight pointer object back in the parent document so updates stay fast.
Avoid embedding base64 blobs in Firestore fields because the serialized string plus field name easily exceeds 1 MiB:
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child(`uploads/${uid}/large-file.bin`).put(fileBlob);
const snapshot = await uploadTask;
const downloadUrl = await snapshot.ref.getDownloadURL();
await firestore.doc(`uploads/${uid}/meta`).set({ url: downloadUrl, size: fileBlob.size });Now only a few metadata fields live in Firestore, while the bytes stay in Cloud Storage where Firestore's document-size limit does not apply. Combine this with Firestore security rules that check the Storage path if you need to enforce ownership.
Field names and Maps count toward the document size, so verbose keys hurt when every document stores similar data. Instead:
1. Replace repeated metadata maps with references to a shared document (e.g. settings/{orgId}) and store only the ID in each record.
2. Trim long field names or rely on fixed keys so the same structure is reused rather than duplicated per document.
3. Use subcollections for optional attributes instead of inflating the root document.
4. Delete unused fields, and rely on Cloud Functions to compute derived data when needed, rather than storing it permanently.
These changes reduce the serialized byte count and keep you safely under the 1 MiB limit.
Firestore counts the entire serialized document when enforcing the 1 MiB limit, including field names, nested maps, arrays, default index entries, and metadata. Field values are separately capped at around 1 MiB - 89 bytes. Subcollections do not share their parent's limit, so they're the standard way to keep logical data together without inflating a single document. The 40,000 index entry limit also forces you to cap the number of fields in a document, so combining index exemptions with smaller documents is often the best way to stay below this limit.
messaging/UNSPECIFIED_ERROR: No additional information available
How to fix "messaging/UNSPECIFIED_ERROR: No additional information available" in Firebase Cloud Messaging
App Check: reCAPTCHA Score Too Low
App Check reCAPTCHA Score Too Low
storage/invalid-url: Invalid URL format for Cloud Storage reference
How to fix invalid URL format in Firebase Cloud Storage
auth/missing-uid: User ID identifier required
How to fix "auth/missing-uid: User ID identifier required" in Firebase
auth/invalid-argument: Invalid parameter passed to method
How to fix "auth/invalid-argument: Invalid parameter passed to method" in Firebase