Short answer: no. Firestore has no undo, no trash, and no revision history. A write replaces the document and a delete removes it.
You can often still get the data back, though. How depends on how long ago it happened and what you set up beforehand.
In the last hour: you probably still can
Even with nothing enabled, Firestore keeps old versions for one hour. Within that hour you can:
- read a document as it was at an earlier time (a “stale read”), or
- clone the whole database at a point in that hour, or
- turn on point-in-time recovery now. The docs say that if you deleted data in the last hour and PITR is off, enabling it within the hour lets you recover it.
So if you just ran the wrong script, don’t wait. Enable PITR first and figure out the rest after:
gcloud firestore databases update --database='(default)' --enable-pitr
(The Firebase docs page currently spells that flag --enable-ptir in one place. It’s --enable-pitr.)
Reading the old version
Stale reads only work from server libraries (Node, Java, Go, PHP), not from the mobile or web SDKs, and they must run in a read-only transaction:
import { getFirestore, Timestamp } from 'firebase-admin/firestore';
const db = getFirestore();
const ref = db.doc('users/u_8f2k1');
const before = Timestamp.fromDate(new Date('2026-10-27T13:00:00Z'));
const old = await db.runTransaction((t) => t.get(ref), {
readOnly: true,
readTime: before,
});
if (old.exists) await ref.set(old.data());
That’s one document. For a bad bulk update you’d run the same query at the old readTime and write every result back. Beyond the last hour, readTime has to be a whole minute.
Up to 7 days: point-in-time recovery
With PITR on, Firestore keeps a version every minute for 7 days. You read old data the same way as above, or clone the database at a minute you pick into a new database and copy what you need from it:
gcloud firestore databases clone \
--source-database='projects/my-project/databases/(default)' \
--snapshot-time='2026-10-27T13:00:00Z' \
--destination-database='recovered'
What to know:
- It only keeps history from when you enabled it. Turning it on after a mistake older than an hour won’t help.
- It needs the Blaze plan. You pay for PITR storage, roughly the size of your database, with no free tier.
- All of this happens in gcloud or the Google Cloud console. The Firebase console can’t do it.
Longer: backups
Scheduled backups run daily or weekly and can be kept up to 14 weeks:
gcloud firestore backups schedules create --database='(default)' \
--recurrence=daily --retention=14w
A restore always goes into a new database, so you end up copying documents back yourself. It’s a disaster-recovery tool, not an undo button.
Without any of that
After the hour, with no PITR, no backup and no export, the data is gone. That’s most small projects.
What I’d actually do
- Production: turn on PITR. Seven days of “oops” is cheap insurance.
- Before any bulk script: export what it touches first. Even a quick NDJSON dump is something to restore from. (Here’s how to export a collection.)
- Test the script on one document, with a
limit(1), before running it on all of them.
Undo in Firedeck
The reason I care about this: Firedeck lets you edit, bulk-edit, delete and import from a phone, and doing that without an undo felt wrong. So since 1.4.0, Firedeck saves every document on your device before it changes it. Each change shows up in history with an Undo button for 30 days.
Undo writes the old version back only if nobody has touched the document since. Documents someone else edited in the meantime are skipped and listed, so you don’t wipe out their work; Restore anyway is there if you’re sure.
It only covers changes made in Firedeck, since it never sees the rest. It isn’t a replacement for PITR, but it covers the most common mistake: the one you made yourself, five minutes ago. History and undo are part of Firedeck Pro. Details in the docs.