Skip to content

Cloud Functions for Firebase: Serverless Backend Code Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Cloud Functions for Firebase: Serverless Backend Code Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Cloud Functions for Firebase runs serverless backend code in response to Firebase events (database changes, auth events) and HTTPS requests, eliminating server management.

What You'll Learn

How to write and deploy Cloud Functions, respond to Firestore document changes, Process auth user creation events, build HTTPS APIs, and handle background tasks.

Why It Matters

Business logic that should not run on the client needs a secure server environment. DodaTech's Antivirus Pro uses Cloud Functions to analyze threat samples, send push notifications, and sync device configurations — all without managing servers.

Real-World Use

When a user uploads a suspicious file, a Cloud Function triggers on the Storage write event, scans the file with a virus detection algorithm, writes results to Firestore, and sends a notification.

flowchart LR
    A["Firestore Write\nNew Scan Result"] --> B["Cloud Function\nTrigger"]
    A --> C["HTTP Request\n/analyze"]
    B --> D["Process Data"]
    C --> D
    D --> E["Write Result\nFirestore"]
    D --> F["Send Push\nNotification"]
    D --> G["Update User\nDashboard"]
    style B fill:#dbeafe,stroke:#2563eb
    style D fill:#bbf7d0,stroke:#16a34a

Function Setup

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

const db = admin.firestore();
const storage = admin.storage();

Firestore Trigger

// Triggered when a new scan result is written
exports.onScanCreated = functions.firestore
  .document("scans/{scanId}")
  .onCreate(async (snap, context) => {
    const scan = snap.data();
    const scanId = context.params.scanId;

    console.log("New scan created:", scanId);
    console.log("Device:", scan.deviceId);
    console.log("Threats found:", scan.threatCount);

    // If critical threat, alert the user
    if (scan.severity === "critical") {
      await db.collection("alerts").add({
        userId: scan.userId,
        scanId: scanId,
        message: "Critical threat detected on your device",
        timestamp: admin.firestore.FieldValue.serverTimestamp(),
        resolved: false
      });
      console.log("Alert created for user:", scan.userId);
    }

    return null;
  });

Auth Trigger

// Send welcome email when a user creates an account
exports.onUserCreated = functions.auth
  .user()
  .onCreate(async (user) => {
    console.log("New user created:", user.uid, user.email);

    // Initialize user profile in Firestore
    await db.collection("users").doc(user.uid).set({
      email: user.email,
      displayName: user.displayName || "User",
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
      subscriptionTier: "free",
      deviceCount: 0
    });

    console.log("User profile initialized");
    return null;
  });

HTTPS Function

// HTTP endpoint for threat analysis
exports.analyzeThreat = functions.https.onCall(async (data, context) => {
  // Verify authentication
  if (!context.auth) {
    throw new functions.https.HttpsError(
      "unauthenticated", "User must be signed in"
    );
  }

  const { fileHash, fileName } = data;

  if (!fileHash || !fileName) {
    throw new functions.https.HttpsError(
      "invalid-argument", "fileHash and fileName required"
    );
  }

  // Simulate threat analysis (replace with real detection)
  console.log("Analyzing:", fileName, "hash:", fileHash);
  const threatScore = Math.random() * 100;
  const isThreat = threatScore > 80;

  // Store result
  await db.collection("analysis").add({
    userId: context.auth.uid,
    fileHash,
    fileName,
    threatScore,
    isThreat,
    analyzedAt: admin.firestore.FieldValue.serverTimestamp()
  });

  console.log("Analysis complete. Threat:", isThreat);

  return {
    fileName,
    isThreat,
    threatScore,
    message: isThreat ? "Threat detected" : "File appears safe"
  };
});

Scheduled Functions

// Daily cleanup of old scan records (runs at midnight)
exports.dailyCleanup = functions.pubsub
  .schedule("0 0 * * *")
  .onRun(async (context) => {
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - 90); // 90 days retention

    const oldScans = await db.collection("scans")
      .where("timestamp", "<", cutoff)
      .limit(500)
      .get();

    let deleted = 0;
    const batch = db.batch();
    oldScans.forEach((doc) => {
      batch.delete(doc.ref);
      deleted++;
    });

    if (deleted > 0) {
      await batch.commit();
    }

    console.log("Cleanup complete. Deleted:", deleted, "old scans");
    return null;
  });

Common Mistakes

1. Cold Starts

Functions that haven't been invoked recently take longer to respond. Keep critical functions warm by setting minInstances on frequently used functions.

2. Not Handling Errors Properly

Unhandled promise rejections cause silent failures. Always use try/catch and return meaningful error objects for HTTPS callable functions.

3. Exceeding Timeout Limits

Functions timeout after 60 seconds (default) or up to 540 seconds (configured). Long-running tasks should use work queues or split into multiple functions.

4. Making Unnecessary Network Calls

Accessing external APIs or databases adds latency. Cache frequent lookups and minimize network dependencies in latency-sensitive functions.

5. Forgetting to Return a Promise

Non-async functions that start async operations may terminate before completion. Always return a promise from your function handler.

Practice Questions

  1. What is a cold start in Cloud Functions?
  2. How do you restrict an HTTPS callable function to authenticated users?
  3. What triggers are available for Cloud Functions?
  4. How do you schedule a function to run periodically?

Answers:

  1. A cold start happens when a function is invoked after being idle. The runtime initializes a new container, adding latency. Set minInstances to keep functions warm.
  2. Check context.auth in the function body. If null, throw an unauthenticated error.
  3. Firestore (create, update, delete, write), Auth (create, delete), Storage (upload, delete), PubSub (scheduled, topic), HTTPS, and more.
  4. Use functions.pubsub.schedule("cron expression").onRun() to run functions on a schedule.

Challenge: Write a Cloud Function that triggers on Firestore threat alert creation, sends a push notification via Firebase Cloud Messaging, logs the notification in a subcollection, and updates the alert status to "notified".

FAQ

What programming languages does Cloud Functions support?

Cloud Functions for Firebase supports Node.js (JavaScript/TypeScript), Python, Go, Java, and .NET through Google Cloud Functions.

How are Cloud Functions priced?

You pay per invocation (calls), compute time (CPU-seconds), and network egress. The free tier includes 2M invocations/month.

Can Cloud Functions access other Google Cloud services?

Yes, Cloud Functions can access any Google Cloud service (BigQuery, Pub/Sub, Cloud Vision API) using the Admin SDK or Google Cloud client libraries.

What is the difference between background functions and HTTP functions?

Background functions are triggered by Firebase events (Firestore, Auth). HTTP functions respond to HTTP requests. Callable functions are a type of HTTP function with Firebase Auth integration.

How do I manage environment-specific configuration?

Use functions.config() to set environment variables per deployment. Set with firebase functions:config:set and access in code via functions.config().key.

Mini Project

Build a serverless threat analysis pipeline: Firestore trigger for new scans, alert creation for critical threats, scheduled daily cleanup of old scans, and an HTTPS callable function for on-demand file analysis.

What's Next

Cloud Function Triggers — explore all trigger types and event-driven patterns.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro