← Back to DevBytes

Firebase Functions: Complete Setup and Configuration Guide

Introduction to Firebase Functions

Firebase Functions, also known as Cloud Functions for Firebase, is a serverless framework that lets you run backend code in response to events triggered by Firebase services, HTTPS requests, or external sources. Instead of managing your own servers, you write single-purpose JavaScript or TypeScript functions and deploy them to Google Cloud's fully managed infrastructure. These functions execute in a secure, auto-scaled environment and can seamlessly interact with Firebase products like Firestore, Authentication, Realtime Database, Storage, and more.

With Firebase Functions, you can handle tasks like sanitizing user-generated content, sending push notifications, processing payments, aggregating data, or integrating third-party APIs — all while keeping your logic close to your Firebase data and events.

Why Firebase Functions Matter

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Firebase Functions bridge the gap between frontend applications and backend logic without requiring you to manage infrastructure. Here are the key reasons they are essential:

Prerequisites and Setup

Before writing your first function, ensure you have the following installed and configured.

1. Node.js and npm

Firebase Functions require Node.js (version 14, 16, or 18+ depending on your runtime). Install the latest LTS version from nodejs.org.

2. Firebase CLI

Install the Firebase command-line tools globally via npm:

npm install -g firebase-tools

3. Firebase Project

Create a new project in the Firebase Console or use an existing one. Enable billing (required for Cloud Functions on the Blaze plan). If you only use functions within the free Spark plan limits (outbound network calls, etc.), you can still develop locally with the Emulator Suite without enabling billing.

4. Log in and Initialize Functions

Authenticate the CLI with your Google account:

firebase login

Create a new directory for your project (or navigate to an existing one) and run:

firebase init functions

The CLI will ask you to select an existing Firebase project, choose between JavaScript or TypeScript, enable ESLint (recommended), and install dependencies. After initialization, you'll have a functions folder containing:

Project Structure Overview

A typical Firebase Functions project looks like this:

my-firebase-app/
├── .firebaserc          # project aliases
├── firebase.json        # configuration for hosting, functions, etc.
├── functions/
│   ├── index.js         # main entry point
│   ├── package.json
│   └── node_modules/
└── ...other folders (e.g., hosting)

All your function definitions live inside index.js (or index.ts if TypeScript). You can split code into separate files for larger projects and import them in the index.

Writing Your First Function

Firebase Functions support several trigger types. We'll cover the most common ones: HTTPS request, Callable function, Firestore document trigger, and a scheduled function.

1. Basic HTTPS Request Function

Respond to standard HTTP requests (GET, POST, etc.). Useful for webhooks, REST APIs, or simple endpoints.

const functions = require('firebase-functions');

exports.helloWorld = functions.https.onRequest((req, res) => {
  res.status(200).send('Hello from Firebase Functions!');
});

Deploy and you’ll get a URL like https://<region>-<project>.cloudfunctions.net/helloWorld.

2. Callable Function (recommended for client calls)

Callable functions are designed to be invoked directly from your mobile or web app using the Firebase SDK. They automatically include authentication context (if the user is logged in) and return structured data.

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

exports.addMessage = functions.https.onCall((data, context) => {
  // data contains parameters sent from the client
  const { text, userId } = data;

  // context.auth contains uid, token, etc.
  if (!context.auth) {
    throw new functions.https.HttpsError('unauthenticated', 'User must be logged in.');
  }

  // Write to Firestore, etc.
  return { success: true, message: `Received: ${text}` };
});

3. Firestore Document Trigger

Run code automatically when a document is created, updated, or deleted in Firestore. Ideal for data aggregation, notifications, or maintaining derived fields.

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

exports.onUserCreate = functions.firestore
  .document('users/{userId}')
  .onCreate(async (snap, context) => {
    const userData = snap.data();
    const userId = context.params.userId;

    // e.g., send a welcome email or create a profile document
    await admin.firestore().collection('userProfiles').doc(userId).set({
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
      email: userData.email,
    });

    console.log(`New user created: ${userId}`);
  });

4. Scheduled Function (pubsub)

Execute a function on a specified schedule (cron job). Perfect for daily reports, cleanup tasks, or periodic syncs.

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

exports.dailyCleanup = functions.pubsub
  .schedule('every 24 hours')
  .onRun(async (context) => {
    // Delete expired tokens or old logs
    const snapshot = await admin.firestore()
      .collection('tempItems')
      .where('expiresAt', '<', new Date())
      .get();

    const batch = admin.firestore().batch();
    snapshot.forEach(doc => batch.delete(doc.ref));
    await batch.commit();

    console.log(`Deleted ${snapshot.size} expired items.`);
    return null;
  });

5. Auth Trigger

React to user creation or deletion in Firebase Authentication.

exports.onUserDelete = functions.auth.user().onDelete(async (user) => {
  // Clean up user-related data in Firestore
  await admin.firestore().collection('userData').doc(user.uid).delete();
  console.log(`Cleaned up data for deleted user: ${user.uid}`);
});

Configuration and Environment Variables

Functions often need access to API keys, secrets, or configuration that shouldn’t be hard-coded. Firebase offers two primary ways to manage these.

1. Firebase Config (legacy, set via CLI)

You can set custom config values using the CLI and access them in your functions via functions.config(). This method works, but values are stored in the Cloud Functions environment and are visible in the Firebase Console under Functions > Environment Configuration.

firebase functions:config:set api_key="YOUR_API_KEY" env="production"

Access in code:

const apiKey = functions.config().api_key;
const environment = functions.config().env;

2. Runtime Environment Variables (.env and .env.yaml)

The modern, recommended approach is to use a .env file (for local emulation) and .env.yaml (for deployed environments). You can define variables and deploy them directly.

Create a .env.yaml in the functions directory:

# .env.yaml (deployed environment)
API_KEY: "production_key_123"
DATABASE_URL: "https://your-project.firebaseio.com"

Deploy with the environment file:

firebase deploy --only functions --env-file .env.yaml

Access in code:

// Environment variables are available via process.env
const apiKey = process.env.API_KEY;
const dbUrl = process.env.DATABASE_URL;

For local development, create a .env file (not committed to version control) with the same keys and use a package like dotenv in your entry point to load them.

Deploying Functions

Deployment uploads your function code to Google Cloud, assigns a trigger URL (for HTTPS functions), and makes them live. You can deploy all functions or specific ones.

Deploy All Functions

firebase deploy --only functions

Deploy a Single Function

firebase deploy --only functions:helloWorld

Deploy Multiple Specific Functions

firebase deploy --only functions:helloWorld,functions:addMessage

Deploy with Environment File

firebase deploy --only functions --env-file .env.yaml

After deployment, the Firebase CLI outputs the live URLs for HTTPS and callable functions. For Firestore/Auth triggers, they start listening immediately.

Testing Functions Locally

The Firebase Emulator Suite lets you run and test your functions locally without deploying. It simulates Firestore, Auth, Storage, Pub/Sub, and more, making development fast and cost-free.

Start the Emulators

firebase emulators:start

By default, the functions emulator runs on port 5001. You can invoke HTTPS functions via http://localhost:5001/<project-id>/<region>/helloWorld. For callable functions, use the client SDK configured to point to the emulator.

Testing Firestore Triggers

With the emulator running, any Firestore write you perform (via client SDK or Admin SDK pointed at the emulator) will automatically trigger your functions. You can see logs in the emulator console.

Use the Emulator UI

Open the interactive Emulator UI at http://localhost:4000 to inspect function invocations, logs, and trigger events.

Monitoring and Logging

Once deployed, you need insight into function execution and errors.

Firebase Console

Go to the Functions dashboard in the Firebase Console. You'll see metrics like invocation count, error rate, and execution time. Each function has a dedicated page with detailed logs.

Firebase CLI Logs

Stream recent logs for all functions:

firebase functions:log

Stream logs for a specific function:

firebase functions:log --only helloWorld

Use the --limit flag to control number of entries.

Google Cloud Console

For advanced monitoring, use the Cloud Functions section of the Google Cloud Console. You can set up alerts, view stack traces, and access Cloud Logging directly.

Best Practices

Follow these guidelines to build efficient, secure, and maintainable Firebase Functions.

Conclusion

Firebase Functions provide a powerful, scalable, and cost-effective way to add server-side logic to your Firebase applications without managing servers. By setting up the Firebase CLI, writing targeted trigger functions, and deploying with proper configuration, you can automate backend processes, integrate third-party services, and secure your app’s data. Embrace best practices like keeping functions lean, handling errors gracefully, and leveraging the local emulator for testing. As your application grows, Firebase Functions can seamlessly scale with it, letting you focus on building features rather than infrastructure.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles