Deploying a Firestore‑Triggered Cloud Function to Copy Documents: Step‑by‑Step Guide
Deploy a Firestore‑triggered Cloud Function that copies documents to another collection, with step‑by‑step setup, verification, and rollback instructions. Includes security rules, IAM roles, and emulator testing.
17 Nov 2025, 22:41 UTC

Desired Outcome
Write a Cloud Function that runs whenever a new document appears in sourceCollection, copies selected fields into targetCollection, and records the operation in a log field. The function should be idempotent, handle transient errors, and be easily rolled back.
Prerequisites
- Firebase Project – A project already created in the Firebase console.
- Node.js 18 – Cloud Functions v4 requires Node 18. Install from nodejs.org.
- Firebase CLI – Install with
npm i -g firebase-toolsand log in:firebase login. - IAM Permissions – The service account
[contact removed]needsroles/datastore.user(read/write) androles/cloudfunctions.invokerfor internal triggers. - Security Rules – Ensure Firestore rules allow the function to read from
sourceCollectionand write totargetCollection.// Firestore rules rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /sourceCollection/{docId} { allow read: if true; // function reads only } match /targetCollection/{docId} { allow write: if request.auth == null; // function writes only } } }
Procedure
1. Create the Function Source
In your project root, create a functions directory and add index.ts (or .js if you prefer plain JS). The following TypeScript example uses the modular SDK:
import { onCreate, DocumentSnapshot } from 'firebase-functions/v2/firestore';
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
initializeApp();
const db = getFirestore();
export const copyOnCreate = onCreate('sourceCollection/{docId}', async (snap: DocumentSnapshot) => {
const data = snap.data();
if (!data) return; // should never happen
const targetDoc = db.collection('targetCollection').doc(snap.id);
const payload = {
name: data.name,
createdAt: new Date(),
sourceRef: snap.ref,
};
try {
await targetDoc.set(payload, { merge: true });
console.log(`Copied ${snap.id} to targetCollection`);
} catch (err) {
console.error(`Failed to copy ${snap.id}:`, err);
throw err; // Cloud Functions will retry automatically
}
});
2. Configure firebase.json
Limit the function bundle to the files that matter to reduce cold‑start latency.
{
"functions": {
"sourceDir": "functions",
"predeploy": ["npm --prefix functions run build"]
}
}
3. Deploy
Run the following from the project root. You need --only functions to avoid redeploying other services.
firebase deploy --only functions
Check the output for a URL and function name. The CLI will also display any lint or build errors.
4. Verify In Production
Use the Firebase console or gcloud functions logs read to confirm the function ran. Then create a test document:
firebase firestore:documents:set sourceCollection/testDoc --data '{"name":"Alice"}'
After a few seconds, query targetCollection/testDoc and confirm the fields match.
Expected Checks
Logs
Look for Copied testDoc to targetCollection in Cloud Functions logs. No error lines should appear.
Data Validation
Run a quick query:
firebase firestore:documents:get targetCollection/testDoc
Verify that name is Alice, createdAt is a timestamp, and sourceRef points back to sourceCollection/testDoc.
Recovery Options
Rollback
If the function introduces unwanted behavior, delete it and redeploy the previous version:
firebase functions:delete copyOnCreate
Then redeploy the last known good commit.
Retry Logic
Cloud Functions automatically retries on failure. To avoid duplicate writes, use set with { merge: true } or check for existence before writing.
Permission Fix
If you encounter permission denied errors, add the roles/datastore.user role to the service account via IAM.
Limitations & Testing
Cold Start
Node 18 functions can take 1–2 seconds to start. Use the Emulator Suite locally to measure latency before live deployment.
Emulator Suite
Set up the Firestore emulator and Cloud Functions emulator:
firebase emulators:start --only functions,firestore
Run the function locally by creating a document in sourceCollection via the emulator console or CLI and verify the target document appears.
Conclusion
By following this guide you can reliably deploy a Firestore‑triggered Cloud Function that copies documents, monitor its operation, and recover quickly if needed. The modular SDK and IAM best practices keep the function lightweight and secure.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.