Cloud Function Triggers: Firestore, Auth, Storage, PubSub & HTTPS Events
In this tutorial, you will learn about Cloud Function Triggers: Firestore, Auth, Storage, PubSub & HTTPS Events. We cover key concepts, practical examples, and best practices to help you master this topic.
Cloud Functions trigger on Firebase and Google Cloud events — each trigger type responds to a specific event source, providing context about what changed and why.
What You'll Learn
How to use each Cloud Functions trigger type: Firestore document triggers, Auth triggers, Storage triggers, PubSub scheduled functions, HTTPS/callable functions, and choosing the right trigger.
Why It Matters
Choosing the wrong trigger leads to missed events, excessive invocations, or complex workarounds. DodaTech uses Firestore triggers for data validation, Auth triggers for user onboarding, and scheduled triggers for cleanup jobs.
Real-World Use
A complete event-driven system: Auth trigger creates a user profile, Firestore trigger processes scan results, Storage trigger analyzes uploaded files, scheduled trigger archives old data.
flowchart TD
A["Auth Create\nonUserCreated"] --> B["Init Profile\nFirestore"]
C["Firestore Write\nonScanCreated"] --> D["Process Scan\nAnalyze Threats"]
E["Storage Upload\nonFileUploaded"] --> F["Virus Scan\nFile Analysis"]
G["PubSub Schedule\nDaily Cleanup"] --> H["Archive Old\nScan Records"]
H --> I["Remove Temp\nFiles"]
style A fill:#dbeafe,stroke:#2563eb
style C fill:#fef3c7,stroke:#d97706
style E fill:#bbf7d0,stroke:#16a34a
style G fill:#fce7f3,stroke:#ec4899
Firestore Triggers
exports.onScanUpdated = functions.firestore
.document("scans/{scanId}")
.onUpdate(async (change, context) => {
const before = change.before.data();
const after = change.after.data();
const scanId = context.params.scanId;
console.log("Scan updated:", scanId);
console.log("Status changed:", before.status, "->", after.status);
if (after.status === "completed" && before.status !== "completed") {
console.log("Scan completed — triggering post-scan actions");
// Send notification, update dashboard, etc.
}
return null;
});
exports.onScanDeleted = functions.firestore
.document("scans/{scanId}")
.onDelete(async (snap, context) => {
const scan = snap.data();
console.log("Scan deleted:", context.params.scanId);
console.log("User:", scan.userId);
// Clean up related data
return null;
});
Auth Triggers
// Triggered when a user account is deleted
exports.onUserDeleted = functions.auth
.user()
.onDelete(async (user) => {
console.log("User deleted:", user.uid);
// Clean up user data
const batch = admin.firestore().batch();
// Delete user profile
batch.delete(admin.firestore().doc(`users/${user.uid}`));
// Delete user devices
const devices = await admin.firestore()
.collection("devices")
.where("userId", "==", user.uid)
.get();
devices.forEach((doc) => batch.delete(doc.ref));
await batch.commit();
console.log("User data cleaned up for:", user.uid);
return null;
});
Storage Triggers
exports.onFileUploaded = functions.storage
.object()
.onFinalize(async (object) => {
const filePath = object.name;
const contentType = object.contentType;
const size = object.size;
console.log("File uploaded:", filePath);
console.log("Type:", contentType, "Size:", size);
// Extract user ID from path: users/{userId}/samples/{filename}
const pathParts = filePath.split("/");
const userId = pathParts[1];
// Store file metadata in Firestore
await admin.firestore().collection("files").add({
userId,
filePath,
contentType,
size,
uploadedAt: admin.firestore.FieldValue.serverTimestamp()
});
console.log("File metadata stored for:", filePath);
return null;
});
PubSub Scheduled Triggers
// Every hour — check for pending scans older than 1 hour
exports.checkStuckScans = functions.pubsub
.schedule("0 * * * *")
.onRun(async (context) => {
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
const stuckScans = await admin.firestore()
.collection("scans")
.where("status", "==", "pending")
.where("createdAt", "<", oneHourAgo)
.get();
console.log("Found", stuckScans.size, "stuck scans");
stuckScans.forEach(async (doc) => {
await doc.ref.update({
status: "failed",
error: "Timed out after 1 hour",
resolvedAt: admin.firestore.FieldValue.serverTimestamp()
});
});
return null;
});
Choosing the Right Trigger
| Trigger | When to Use | Latency |
|---|---|---|
| Firestore onCreate | Process new data | Near real-time |
| Firestore onUpdate | React to changes | Near real-time |
| Auth onCreate | User onboarding | Near real-time |
| Storage onFinalize | File processing | Near real-time |
| PubSub schedule | Cron Jobs | Scheduled |
| HTTPS onCall | Client request | Request-response |
| HTTPS onRequest | REST API endpoint | Request-response |
Common Mistakes
1. Mutating the Same Document in a Trigger
Writing to the same document that triggered the function can cause infinite loops. Use a flag field or write to a different path.
2. Not Handling Multiple Triggers on the Same Event
Multiple functions can trigger on the same event. Design each function to be independent and idempotent.
3. Overusing Auth Triggers
Auth triggers fire for admin SDK operations too. Admin.createUser() triggers onCreate. Be aware of this when provisioning accounts.
4. Ignoring Event Order
Firestore events are not guaranteed to arrive in order. An onDelete may arrive before the onCreate processed fully. Use idempotent operations.
5. Forgetting to Set Timeout for Scheduled Functions
Scheduled functions have a 60-second default timeout. Long cleanup jobs need increased timeout configuration.
Practice Questions
- What is the difference between
onCreateandonWriteFirestore triggers? - How do you prevent infinite loops with Firestore triggers?
- What events can Auth triggers respond to?
- How do you schedule a function to run every 30 minutes?
Answers:
onCreatefires only when a document is created.onWritefires on create, update, and delete events.- Add a
triggeredByFunctionfield or use a separate_processedfield to detect and skip function-originated writes. - Auth triggers respond to
onCreate(user signed up) andonDelete(user deleted). - Use
functions.pubsub.schedule("*/30 * * * *").onRun()with a cron expression.
Challenge: Build a complete trigger system: Auth onCreate creates user profile, Firestore onCreate processes threat alerts, Storage onFinalize analyzes uploaded files, and a 24-hour cleanup removes resolved alerts.
FAQ
Mini Project
Build an event-driven system: Auth trigger initializes user profile + default device, Firestore trigger processes scan completions and awards badges, Storage trigger logs file uploads, scheduled trigger sends weekly digests.
What's Next
Callable Functions — build client-callable HTTPS functions with auth integration.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro