FirexportGuides
How to rename a Firestore document (change its ID)
Firestore can’t rename a document. A document’s ID is part of its path, and neither the Firebase console nor the SDKs have a way to change it. Renaming means creating the document again under the new ID and deleting the old one, together with everything in its subcollections, which deleting a document doesn’t touch. There are three ways to do it, depending on how much sits under the document.
Updated October 27, 2026. Firexport, the extension in method 1, is ours. Methods 2 and 3 don’t need it.
The short answer
- One document, with its subcollections, right now: change the ID from the console’s panel view with a browser extension. Method 1
- More than 250 documents under it, or many documents to rename: a short Admin SDK script. Method 2
- A small document with no subcollections, and nothing to install: copy it by hand in the console. Method 3
| 1. Console + extension | 2. Admin SDK script | 3. By hand in the console | |
|---|---|---|---|
| Setup | Install a Chrome extension, connect your Google account | Node.js and Google Cloud credentials | None |
| Subcollections | Moved, at every depth | Moved, at every depth | Left behind |
| Field values | Kept exactly | Kept, except a double like 2.0, which becomes an integer | Typed again |
| All or nothing | Yes, one write | Yes, in one batch (up to 10 MiB) | No |
| Size | Up to 250 documents | No limit | A few fields |
1. Change the ID from the Firebase console with Firexport
Firexport is a free Chrome extension that adds Change document ID to the ⋮ menu of each document in Firestore’s panel view. It moves the document and everything in its subcollections to the new ID in a single write, so all of it happens or none of it. It writes with a Google account you connect, so there is no service account key or code to set up.
- Install Firexport from the Chrome Web Store.
- In the Firebase console, open Firestore Database > Data in Panel view and click the collection that holds the document.
- Hover the document in the list and click the ⋮ that appears to the left of its ID, then Change document ID.
- The first time, the window asks you to Connect Google account: pick the account signed in to the console and allow access in Google’s window.
- Type the New document ID and click Change ID. A document without subcollections moves right away.
- If it has subcollections, Firexport reads them first and shows how many documents will move, how many writes that takes and how many reads it took to check. Click Move. The console then opens the document under its new ID.
What stops a move
- A document already at the new ID, or under it. Firexport never overwrites: the write is refused and nothing changes.
- A change to any of the documents after Firexport read them. The old content would otherwise land under the new ID while the new content was deleted, so nothing is written and you can try again.
- More than 250 documents, or more than one write can carry (10 MiB). Firexport stops before writing anything; use method 2.
- An ID Firestore doesn’t allow: one that contains
/, is just.or.., starts and ends with__, or is over 1,500 bytes. Spaces at either end are part of the ID, so the box keeps them.
Every field keeps its exact value and type, because Firexport writes what it read from Firestore instead of what the console shows. The writes use the connected account’s permissions, so Security Rules don’t apply. The documents go from your browser straight to Google, and never to us. Change document ID is free on every plan.
Change a Firestore document’s ID from the console, with its subcollections, in one write.
2. Move it with an Admin SDK script
For a document with more than 250 documents under it, or for renaming many documents, a Node.js script with the Firebase Admin SDK does the same move. The one below reads the document and every subcollection under it, then creates each one at the new path and deletes the old ones. The new path can be in another collection too, so the same script moves a document. It needs an account that can write to Firestore: a project Owner or Editor, or the Cloud Datastore User role.
- Install the SDK:
npm install firebase-admin - Sign in for local credentials:
gcloud auth application-default login. On a server, pointGOOGLE_APPLICATION_CREDENTIALSat a service account key instead. - Save the script below as
rename-document.mjs, replaceyour-project-id, and runnode rename-document.mjs users/alice users/alice-smith.
// Usage: node rename-document.mjs users/alice users/alice-smith → moves users/alice and everything under it
// Firestore has no rename: this creates the document at the new path with all its subcollections, then deletes the old ones.
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
initializeApp({ projectId: 'your-project-id' });
const db = getFirestore();
db.settings({ useBigInt: true }); // integers past 2^53 would otherwise lose their last digits on the way through
const [from, to] = process.argv.slice(2);
if (!from || !to) throw new Error('Usage: node rename-document.mjs <document path> <new document path>');
if (to === from || to.startsWith(`${from}/`)) throw new Error('The new path must be outside the document you move');
// true: one batch, so every write happens or none does (up to 10 MiB of data in all).
// false: for more than that. Copies everything first and deletes the old documents only once every copy is written.
const ONE_BATCH = true;
// The document and every document under it, in subcollections of subcollections too. listDocuments() also returns
// places that have subcollections but no fields, so the walk reaches what is under them; the places themselves aren't copied.
async function collect(ref, found) {
const snapshot = await ref.get();
if (snapshot.exists) found.push(snapshot);
for (const collection of await ref.listCollections()) {
for (const child of await collection.listDocuments()) await collect(child, found);
}
return found;
}
const docs = await collect(db.doc(from), []);
if (docs[0]?.ref.path !== from) throw new Error(`${from} doesn't exist`);
const target = (doc) => db.doc(to + doc.ref.path.slice(from.length));
if (ONE_BATCH) {
// create() fails if a document is already at the new path, and lastUpdateTime fails if one changed after it was read.
// Either way Firestore rejects the whole batch and nothing is written.
const batch = db.batch();
for (const doc of docs) batch.create(target(doc), doc.data());
for (const doc of docs) batch.delete(doc.ref, { lastUpdateTime: doc.updateTime });
await batch.commit();
} else {
// BulkWriter keeps under Firestore's rate limits and retries what can be retried, but it isn't all or nothing.
const writer = db.bulkWriter();
const failures = [];
for (const doc of docs) {
writer.create(target(doc), doc.data()).catch((error) => failures.push(`${doc.ref.path}: ${error.message}`));
}
await writer.flush();
if (failures.length) {
failures.forEach((failure) => console.log(failure));
throw new Error('Some copies failed, so nothing was deleted. Delete the copies that were written, then try again.');
}
for (const doc of docs) {
writer.delete(doc.ref, { lastUpdateTime: doc.updateTime }).catch((error) => failures.push(`${doc.ref.path}: ${error.message}`));
}
await writer.close();
failures.forEach((failure) => console.log(`Not deleted, ${failure}`));
}
console.log(`Moved ${docs.length} documents from ${from} to ${to}`);listDocuments()also returns a place that has subcollections but no fields of its own, the italic IDs in the console, so the script reaches the documents under it. The place itself isn’t copied: it appears at the new path once its subcollections do.- With
ONE_BATCHon, every create and delete goes in one batch. If a document already exists at the new path, or one changed after the script read it, Firestore rejects the batch and nothing is written. - A batch can carry up to 10 MiB. For a bigger tree, set
ONE_BATCHtofalse: the script copies everything withBulkWriterand deletes the old documents only if every copy was written. That isn’t all or nothing, so don’t write to those documents while it runs. - Like method 1, it bypasses Security Rules. Timestamps, references, geopoints and bytes keep their types, and
useBigIntkeeps integers past 253 exact. One thing the Admin SDK can’t keep: a double with no fraction, such as2.0, is read as a plain number and written back as the integer2.
3. Copy it by hand in the console
For a document with a few fields and no subcollections, the console alone will do. It takes two writes that aren’t tied together, and you type every value again.
- Open the document and note each field’s name, type and value.
- In the same collection, click Add document, enter the new ID in Document ID, and add the same fields with the same types. Click Save.
- Check the new document, then open the ⋮ menu on the old one and click Delete document.
Watch the types as you go: a number typed into a string field stays a string, and a timestamp has to be entered again with the timestamp type. Subcollections don’t come along. Each one would have to be copied the same way, a document at a time.
What a new ID changes
Whichever way you move it, the document under the new ID is a new document. A few things follow from that.
- Creation time. Each moved document gets a new create and update time.
- References. Reference fields in other documents still point to the old path, and so do IDs stored as strings, such as an
ownerId. Update them yourself. - Cloud Functions and listeners. Each moved document fires the create and delete triggers, and apps listening to the collection see one document removed and another added.
- Cost. Each moved document is one write and one delete on the bill, plus the reads to find and read it.
FAQ
Can you rename a document in Firestore?
Not directly. Firestore has no rename operation, and a document’s ID can’t change once it is created. To rename one, create a document with the new ID and the same data, then delete the old one. Firexport’s Change document ID and the Admin SDK script above do both in one write.
Does renaming a document move its subcollections?
Only if you move them too. Subcollections belong to the document’s path, not its data, so copying the fields leaves them behind, and deleting the old document doesn’t delete them either. Firexport and the script above move every subcollection at every depth with the document.
Can I rename a collection in Firestore?
No. A collection exists only through the documents in it, so renaming one means moving every document to the new collection name. Neither the console nor Firexport does that in one step; a script that runs the move above for each document does.
What happens to references to the old document?
They keep pointing to the old path, which no longer exists after the move. Firestore doesn’t update reference fields or IDs stored in other documents, so find and update them after you rename.
How much does renaming a Firestore document cost?
Each moved document is one write and one delete, plus the reads to find it and its subcollections. Firexport shows the number before you press Move. On the free Spark plan that comes out of the daily 20,000 writes and 20,000 deletes.
