|
| 1 | +## Key Guidelines |
| 2 | + |
| 3 | +- Always use 2nd-gen functions for new development. |
| 4 | +- Use 1st-gen functions _only_ for Analytics and basic Auth triggers, since those aren't supported by 2nd gen. |
| 5 | +- Use `firebase-functions` SDK version 6.0.0 and above |
| 6 | +- Use top-level imports (e.g., `firebase-functions/https`). These are 2nd gen by default. If 1st gen is required (Analytics or basic Auth triggers), import from the `firebase-functions/v1` import path. |
| 7 | + |
| 8 | +## Configuration: Use Secret Params for API Keys |
| 9 | + |
| 10 | +For sensitive information like API keys (e.g., for LLMs, payment providers, etc.), **always** use `defineSecret`. This stores the value securely in Cloud Secret Manager. |
| 11 | + |
| 12 | +```typescript |
| 13 | +import { onRequest } from "firebase-functions/https"; |
| 14 | +import { logger } from "firebase-functions/logger"; |
| 15 | +import { defineString, defineSecret } from "firebase-functions/params"; |
| 16 | + |
| 17 | +// Securely define an LLM API key |
| 18 | +const LLM_API_KEY = defineSecret("LLM_API_KEY"); |
| 19 | + |
| 20 | +// Example function that uses the secret |
| 21 | +export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => { |
| 22 | + const apiKey = LLM_API_KEY.value(); |
| 23 | + |
| 24 | + // Use the apiKey to make a call to the LLM service |
| 25 | + logger.info("Calling LLM with API key."); |
| 26 | + |
| 27 | + // insert code here to call LLM... |
| 28 | + |
| 29 | + res.send("LLM API call initiated."); |
| 30 | +}); |
| 31 | +``` |
| 32 | + |
| 33 | +The CLI will prompt for secret's value at deploy time. Alternatively, a human can set the secret using the Firebase CLI command: |
| 34 | + |
| 35 | +```bash |
| 36 | +firebase functions:secrets:set <SECRET_NAME> |
| 37 | +``` |
| 38 | + |
| 39 | +If you see an API key being accessed with `functions.config` in existing functions code, offer to upgrade to params. |
| 40 | + |
| 41 | +## Use the Firebase Admin SDK |
| 42 | + |
| 43 | +To interact with Firebase services like Firestore, Auth, or RTDB from within your functions, you need to initialize the Firebase Admin SDK. Call `initializeApp` without any arguments so that Application Default Credentials are used. |
| 44 | + |
| 45 | +1. **Install the SDK:** |
| 46 | + |
| 47 | + ```bash |
| 48 | + npm i firebase-admin |
| 49 | + ``` |
| 50 | + |
| 51 | +2. **Initialize in your code:** |
| 52 | + |
| 53 | + ```typescript |
| 54 | + import * as admin from "firebase-admin"; |
| 55 | + import { onInit } from "firebase-functions"; |
| 56 | +
|
| 57 | + onInit(() => { |
| 58 | + admin.initializeApp(); |
| 59 | + }); |
| 60 | + ``` |
| 61 | +
|
| 62 | + This should be done once at the top level of your `index.ts` file. |
| 63 | +
|
| 64 | +## Common Imports |
| 65 | +
|
| 66 | +```typescript |
| 67 | +import { onRequest, onCall, onCallGenkit } from "firebase-functions/https"; |
| 68 | +import { onDocumentUpdated } from "firebase-functions/firestore"; |
| 69 | +import { onNewFatalIssuePublished } from "firebase-functions/alerts/crashlytics"; |
| 70 | +import { onValueWritten } from "firebase-functions/database"; |
| 71 | +import { onSchedule } from "firebase-functions/scheduler"; |
| 72 | +const { onTaskDispatched } = require("firebase-functions/tasks"); |
| 73 | +import { onObjectFinalized } from "firebase-functions/storage"; |
| 74 | +import { onMessagePublished } from "firebase-functions/pubsub"; |
| 75 | +import { beforeUserSignedIn } from "firebase-functions/identity"; |
| 76 | +import { onTestMatrixCompleted } from "firebase-functions/testLab"; |
| 77 | +import { logger, onInit } from "firebase-functions"; |
| 78 | +import { defineString, defineSecret } from "firebase-functions/params"; |
| 79 | +``` |
| 80 | +
|
| 81 | +A human can find code samples for these triggers in the [functions-samples repository](https://github.com/firebase/functions-samples/tree/main/Node). |
| 82 | +
|
| 83 | +## 1st-gen Functions (Legacy Triggers) |
| 84 | +
|
| 85 | +Use the `firebase-functions/v1` import for Analytics and basic Auth triggers. These aren't supported in 2nd gen. |
| 86 | +
|
| 87 | +```typescript |
| 88 | +import * as functionsV1 from "firebase-functions/v1"; |
| 89 | +
|
| 90 | +// v1 Analytics trigger |
| 91 | +export const onPurchase = functionsV1.analytics.event("purchase").onLog(async (event) => { |
| 92 | + logger.info("Purchase event", { value: event.params?.value }); |
| 93 | +}); |
| 94 | +
|
| 95 | +// v1 Auth trigger |
| 96 | +export const onUserCreate = functionsV1.auth.user().onCreate(async (user) => { |
| 97 | + logger.info("User created", { uid: user.uid }); |
| 98 | +}); |
| 99 | +``` |
| 100 | +
|
| 101 | +## Development Commands |
| 102 | +
|
| 103 | +```bash |
| 104 | +# Install dependencies |
| 105 | +npm install |
| 106 | +
|
| 107 | +# Compile TypeScript |
| 108 | +npm run build |
| 109 | +
|
| 110 | +# Run emulators for local development |
| 111 | +# This is a long-running command. A human can run this command themselves to start the emulators: |
| 112 | +firebase emulators:start --only functions |
| 113 | +
|
| 114 | +# Deploy functions |
| 115 | +firebase deploy --only functions |
| 116 | +``` |
0 commit comments