Useful Commands and Best Practices
Most Common Firebase-Tools Commands
1. Functions Deployment
# Deploy all functions
firebase deploy --only functions
# Deploy a specific function
firebase deploy --only functions:functionName
# Deploy with security check
firebase deploy --only functions --force
2. Logs Visualisation
# View logs in real-time
firebase functions:log
# Logs for a specific function
firebase functions:log --only functionName
# Logs with time filter
firebase functions:log --since 2h
3. Emulators for Local Development
# Start all emulators
firebase emulators:start
# Start only functions emulator
firebase emulators:start --only functions
# Start with custom port
firebase emulators:start --only functions --functions-port 5001
4. Other Useful Commands
# Login/logout
firebase login
firebase logout
# Project initialisation
firebase init functions
# List projects
firebase projects:list
# Switch active project
firebase use project-id
Best Practices for Firebase Functions
1. Project Structure
functions/
├── lib/ # Main folder for functions
│ ├── processPdData.js # Classic Firebase functions
│ ├── verifyAndCreateToken.js # Classic Firebase functions
│ ├── sendMail.js # Classic Firebase functions
│ ├── getLocationFromIP.js # Classic Firebase functions
│ ├── notifications/ # Subfolder for notification functions
│ │ ├── supportRequests.js
│ │ ├── weeklySkuAssigned.js
│ │ ├── licenseHasExpired.js
│ │ └── quotationRequest.js
│ └── service/ # Configuration/service files
│ ├── staging-firebase-adminsdk.json # Staging service account
│ └── production-firebase-adminsdk.json # Production service account
└── index.js # Main export file
Example of file in lib/ folder
// lib/notifications/supportRequests.js
const { onRequest } = require("firebase-functions/v2/https");
const { db } = require("../config/firebase");
exports.processSupportRequest = onRequest(async (req, res) => {
// CORS configuration
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
res.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
// Handle preflight OPTIONS request
if (req.method === "OPTIONS") {
return res.status(204).send("");
}
try {
// Verify it's a POST request
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed. Use POST." });
}
const { supportRequestId } = req.body;
if (!supportRequestId) {
return res.status(400).json({ error: "Support request ID required." });
}
// Function logic
const supportRequestRef = db
.collection("SupportRequests")
.doc(supportRequestId);
const supportRequestDoc = await supportRequestRef.get();
if (!supportRequestDoc.exists) {
return res.status(404).json({ error: "Support request not found." });
}
// Process the request...
const result = await processRequest(supportRequestDoc.data());
res.status(200).json({
success: true,
message: "Request processed successfully",
data: result,
});
} catch (error) {
console.error("Error processing support request:", error);
res.status(500).json({
error: "Internal server error",
details: error.message,
});
}
});
2. Export in index.js file
// index.js - Simple export example
// Import classic functions from lib/ folder
const { processPdData } = require("./lib/processPdData");
const { verifyAndCreateToken } = require("./lib/verifyAndCreateToken");
const { sendMail } = require("./lib/sendMail");
// Import notification functions from lib/notifications/ subfolder
const {
processSupportRequest,
} = require("./lib/notifications/supportRequests");
// Export to make them available as Firebase Functions
exports.processPdData = processPdData;
exports.verifyAndCreateToken = verifyAndCreateToken;
exports.sendMail = sendMail;
exports.processSupportRequest = processSupportRequest;
3. Best Practices for Performance
Global Initialisation
// ✅ Good: global initialisation
const admin = require("firebase-admin");
admin.initializeApp();
exports.myFunction = functions.https.onRequest((req, res) => {
// Admin connection is already ready
});
Cold Start Management
// ✅ Minimise dependencies
const functions = require("firebase-functions");
// ✅ Use lazy loading for heavy modules
exports.heavyFunction = functions.https.onRequest(async (req, res) => {
const heavyModule = require("./heavy-module"); // Load only when necessary
});
4. Best Practices for Security
Input Validation
exports.secureFunction = functions.https.onRequest((req, res) => {
// ✅ Always validate input
if (!req.body.userId || typeof req.body.userId !== "string") {
return res.status(400).json({ error: "Invalid userId" });
}
// ✅ Sanitise data
const userId = req.body.userId.trim();
});
Authentication
exports.authenticatedFunction = functions.https.onRequest(async (req, res) => {
try {
// ✅ Verify JWT token
const token = req.headers.authorization?.replace("Bearer ", "");
const decodedToken = await admin.auth().verifyIdToken(token);
// Proceed with function logic
} catch (error) {
return res.status(401).json({ error: "Unauthorised" });
}
});
5. Best Practices for Maintainability
CamelCase Nomenclature
// ✅ Use camelCase for function and variable names
exports.getUserProfile = functions.https.onRequest((req, res) => {
const userEmail = req.body.email;
const isValidEmail = validateEmail(userEmail);
});
Error Handling
exports.robustFunction = functions.https.onRequest(async (req, res) => {
try {
// Main logic
const result = await performOperation();
res.json({ success: true, data: result });
} catch (error) {
// ✅ Detailed logging for debugging
console.error("Error in robustFunction:", error);
// ✅ User-friendly response
res.status(500).json({
error: "Internal server error",
timestamp: new Date().toISOString(),
});
}
});
Timeout and Resource Management
// ✅ Set appropriate timeouts
exports.longRunningFunction = functions
.runWith({ timeoutSeconds: 300, memory: "1GB" })
.https.onRequest(async (req, res) => {
// Operations requiring more time/memory
});
6. Monitoring and Debugging
// ✅ Use structured logging
const { logger } = require("firebase-functions");
exports.monitoredFunction = functions.https.onRequest((req, res) => {
logger.info("Function started", {
userId: req.body.userId,
timestamp: Date.now(),
});
try {
// Function logic
logger.info("Operation completed successfully");
} catch (error) {
logger.error("Operation failed", { error: error.message });
}
});