iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Cloud Functions

Cloud Functions for Firebase run your backend code in response to HTTPS calls, Firestore writes, Auth events, Pub/Sub messages, scheduled cron, and more. The v2 SDK simplifies regions, concurrency, and secrets — it’s the easiest way to add a server-side surface to a Firebase app without managing servers.

HTTPS, triggers, secrets, scheduled

EXAMPLE
// 1) Setup
// firebase init functions
// Choose TypeScript, install deps
// functions/src/index.ts
import { onRequest, onCall } from 'firebase-functions/v2/https';
import { onDocumentCreated } from 'firebase-functions/v2/firestore';
import { onObjectFinalized } from 'firebase-functions/v2/storage';
import { beforeUserCreated } from 'firebase-functions/v2/identity';
import { onMessagePublished } from 'firebase-functions/v2/pubsub';
import { onSchedule } from 'firebase-functions/v2/scheduler';
import { setGlobalOptions } from 'firebase-functions/v2';
import { defineSecret } from 'firebase-functions/params';
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
import { getAuth } from 'firebase-admin/auth';

setGlobalOptions({ region: 'australia-southeast1', maxInstances: 10 });
initializeApp();

// 2) HTTPS function (REST endpoint)
export const hello = onRequest({ cors: true }, async (req, res) => {
    res.json({ msg: `hello, ${req.query.name ?? 'world'}` });
});
// Deploy: firebase deploy --only functions:hello
// URL: https://australia-southeast1-<project>.cloudfunctions.net/hello

// 3) Callable function — client calls with the Firebase SDK; auth + JSON handled for you
import { HttpsError } from 'firebase-functions/v2/https';

export const createPost = onCall(async (req) => {
    if (!req.auth) throw new HttpsError('unauthenticated', 'Sign in required');
    const { title, body } = req.data ?? {};
    if (!title?.length) throw new HttpsError('invalid-argument', 'title required');
    const docRef = await getFirestore().collection('posts').add({
        title,
        body,
        authorId: req.auth.uid,
        createdAt: new Date(),
    });
    return { id: docRef.id };
});

// Client (web)
import { getFunctions, httpsCallable } from 'firebase/functions';
const fns = getFunctions(app, 'australia-southeast1');
const create = httpsCallable(fns, 'createPost');
await create({ title: 'Hi', body: 'World' });

// 4) Firestore trigger — react to data changes
export const onUserCreated = onDocumentCreated('users/{uid}', async (event) => {
    const user = event.data?.data();
    if (!user) return;
    await getFirestore().collection('audit').add({
        action: 'user.created',
        uid: event.params.uid,
        at: new Date(),
    });
});

// 5) Auth trigger
export const blockBadDomains = beforeUserCreated((event) => {
    if (event.data.email?.endsWith('@blocked.example')) {
        throw new HttpsError('permission-denied', 'Domain not allowed');
    }
});

// 6) Storage trigger — resize uploaded images
export const onImageUploaded = onObjectFinalized({ region: 'australia-southeast1' }, async (event) => {
    const { bucket, name, contentType } = event.data;
    if (!contentType?.startsWith('image/')) return;
    if (name?.includes('thumb_')) return;            // avoid recursion
    // resize logic …
});

// 7) Pub/Sub trigger
export const handleSignupEvent = onMessagePublished({ topic: 'signups' }, async (event) => {
    const data = event.data.message.json;
    // process the message
});

// 8) Scheduled function
export const dailySummary = onSchedule(
    { schedule: 'every day 06:00', timeZone: 'Australia/Sydney' },
    async () => {
        const db = getFirestore();
        // generate yesterday's report and email it
    },
);

// 9) Secrets
const SENDGRID_KEY = defineSecret('SENDGRID_API_KEY');

export const sendNewsletter = onSchedule(
    { schedule: 'every monday 08:00', secrets: [SENDGRID_KEY] },
    async () => {
        const key = SENDGRID_KEY.value();
        // call sendgrid with `key`
    },
);
// Set: firebase functions:secrets:set SENDGRID_API_KEY

// 10) Configuration options
export const heavy = onRequest(
    {
        region: 'us-central1',
        memory: '1GiB',                 // 256MiB / 512MiB / 1GiB / 2GiB / 4GiB / 8GiB
        cpu:     1,
        timeoutSeconds: 540,            // max 60 min for v2
        concurrency: 80,
        maxInstances: 100,
        minInstances: 1,                // keep warm to avoid cold starts ($$)
        ingressSettings: 'ALLOW_INTERNAL_ONLY',
    },
    async (req, res) => { /* … */ },
);

// 11) CORS + auth on HTTPS
import cors from 'cors';
const corsHandler = cors({ origin: ['https://app.example.com'], credentials: true });
export const api = onRequest({ cors: false }, (req, res) => {
    corsHandler(req, res, async () => {
        // verify ID token
        const idToken = req.headers.authorization?.replace('Bearer ', '');
        if (!idToken) return res.sendStatus(401);
        try {
            const decoded = await getAuth().verifyIdToken(idToken);
            res.json({ uid: decoded.uid });
        } catch (e) {
            res.sendStatus(401);
        }
    });
});

// 12) Emulator suite for local dev
// firebase emulators:start --only functions,firestore
// Functions hot-reload; triggers fire from emulated Firestore/Auth/Storage.
// Same code runs in prod with no changes.

// 13) Deployment
// firebase deploy --only functions                   # all functions
// firebase deploy --only functions:hello,functions:api  # selective
// firebase functions:delete oldFunc                   # remove a deployed function

// 14) Logs + monitoring
// firebase functions:log --tail
// Cloud Logging in GCP console for filtering and metrics.
// Set up uptime checks for HTTPS endpoints; alerts on error rate.

// 15) Cost tips
// • minInstances costs money (always-running) — use only for latency-sensitive endpoints
// • concurrency > 1 (v2 default 80) shares one instance among many requests → cheaper
// • Reduce cold starts: keep deps slim, use top-level await sparingly, prefer ESM
// • Choose region close to users + Firestore data → less egress
// • Watch egress to internet vs Google services

// 16) Common bugs
// • Forgot to call initializeApp() → admin SDK throws
// • Cold start hits user on first request → minInstances or warm-up requests
// • Region mismatch between client + function → cross-region call adds latency
// • Function throws but client gets timeout → throw HttpsError with code for callables
// • Storage trigger recursion (resize → upload → re-trigger) → guard with name prefix/path
// • Background trigger lacks idempotency → retries duplicate side effects; use idempotency keys
// • Secret used before defining → undefined; ensure secret in 'secrets' array on function options
// • Heavy npm dep bundle → slow cold starts; trim deps + use esbuild bundling for v2

Why it matters

Cloud Functions v2 covers HTTPS, callable, Firestore, Auth, Storage, Pub/Sub, and cron triggers from one SDK. Pick the right region close to your users and data, lean on onCall for client-callable endpoints (it handles auth + CORS), keep secrets in defineSecret instead of env files, and guard background triggers against recursion + non-idempotent retries.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// functions/src/index.ts
import { onDocumentCreated } from 'firebase-functions/v2/firestore';
export const onPostCreate = onDocumentCreated('posts/{id}', (event) => {
    const post = event.data?.data();
    console.log('new post', post?.title);
});
Try it Yourself »

Exercise

Trigger on doc creation.

export const fn = ('posts/{id}', ev => { });

Test yourself

Q1. Cloud Functions for Firebase run on…
Q2. The supported runtimes include…
Q3. A Firestore "doc created" trigger uses…

Discussion

Loading…