From 94fdcef8d247c372cabebae0ed6c8b11ea183fe1 Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 26 Sep 2025 10:14:09 -0400 Subject: [PATCH 01/12] gemini cli-assisted first-pass --- .guides/config.json | 9 +++ .guides/examples/index.md | 5 ++ .guides/setup.md | 74 ++++++++++++++++++ .guides/upgrade.md | 154 ++++++++++++++++++++++++++++++++++++++ .guides/usage.md | 90 ++++++++++++++++++++++ 5 files changed, 332 insertions(+) create mode 100644 .guides/config.json create mode 100644 .guides/examples/index.md create mode 100644 .guides/setup.md create mode 100644 .guides/upgrade.md create mode 100644 .guides/usage.md diff --git a/.guides/config.json b/.guides/config.json new file mode 100644 index 000000000..1d33a3256 --- /dev/null +++ b/.guides/config.json @@ -0,0 +1,9 @@ +{ + "description": "A set of guides for Cloud Functions for Firebase.", + "mcpServers": { + "firebase": { + "command": "firebase", + "args": ["mcp:server"] + } + } +} \ No newline at end of file diff --git a/.guides/examples/index.md b/.guides/examples/index.md new file mode 100644 index 000000000..528dc18be --- /dev/null +++ b/.guides/examples/index.md @@ -0,0 +1,5 @@ +# Firebase Functions Samples + +For useful and minimal samples for various function triggers, please refer to the official Firebase Functions quickstarts repository on GitHub: + +[https://github.com/firebase/functions-samples/tree/main/Node/quickstarts](https://github.com/firebase/functions-samples/tree/main/Node/quickstarts) diff --git a/.guides/setup.md b/.guides/setup.md new file mode 100644 index 000000000..dfcb33abf --- /dev/null +++ b/.guides/setup.md @@ -0,0 +1,74 @@ +# Firebase Functions Setup Guide + +This guide provides a step-by-step process for setting up a new Firebase Functions project, tailored for a coding agent. + +### **Step 1: Initialize Firebase Project** + +If you haven't already, initialize your Firebase project. The agent should have the `firebase-tools` CLI installed. + +```bash +# One-time setup for a new project +firebase login +firebase init functions +``` +During initialization, select `TypeScript`. + +### **Step 2: Install Dependencies** + +Navigate to the `functions` directory and install the necessary NPM packages. + +```bash +cd functions +npm install +``` + +### **Step 3: Create a v2 HTTP Function** + +Replace the contents of `src/index.ts` with the following code to create a simple, modern v2 HTTP endpoint. + +```typescript +import {onRequest} from "firebase-functions/v2/https"; +import * as logger from "firebase-functions/logger"; +import {defineString} from "firebase-functions/params"; + +// Define a configuration parameter for a greeting +const greeting = defineString("GREETING", {default: "Hello"}); + +export const helloWorld = onRequest((request, response) => { + logger.info("Request received!", {structuredData: true}); + response.send(`${greeting.value()} from Firebase!`); +}); +``` + +**Key points for the agent:** +* Always import from `firebase-functions/v2/*` for new functions. +* Use `logger` for structured logging. +* Use `defineString`, `defineInt`, `defineSecret` for environment configuration instead of `functions.config()`. + +### **Step 4: Build TypeScript** + +Compile your TypeScript code to JavaScript. + +```bash +npm run build +``` + +### **Step 5: Local Development and Testing** + +Use the Firebase Emulators to test your function locally before deploying. + +```bash +# Start the functions emulator +firebase emulators:start --only functions +``` +The agent can then interact with the function at the local URL provided by the emulator. + +### **Step 6: Deploy to Firebase** + +Once testing is complete, deploy the function to your Firebase project. + +```bash +# Deploy only the functions +firebase deploy --only functions +``` +The agent will be prompted to set any parameters defined with `defineString` or other `define` functions that do not have a default value. diff --git a/.guides/upgrade.md b/.guides/upgrade.md new file mode 100644 index 000000000..02bdf2d80 --- /dev/null +++ b/.guides/upgrade.md @@ -0,0 +1,154 @@ +# Upgrading Firebase Functions to 2nd Gen + +This guide summarizes the process of migrating Cloud Functions from 1st to 2nd generation. You can migrate functions incrementally, running both generations side-by-side. + +## 1. Update Dependencies + +Update your `firebase-functions` and `firebase-admin` SDKs, and ensure you are using a recent version of the Firebase CLI. + +## 2. Modify Imports + +Update your import statements to use the `v2` subpackage. + +**Before (1st Gen):** +```typescript +import * as functions from "firebase-functions"; +``` + +**After (2nd Gen):** +```typescript +import * as functions from "firebase-functions/v2"; +``` + +## 3. Update Trigger Definitions + +The SDK is now more modular. Update your trigger definitions accordingly. + +### HTTP Triggers + +**Before (1st Gen):** +```typescript +export const webhook = functions.https.onRequest((request, response) => { + // ... +}); +``` + +**After (2nd Gen):** +```typescript +import {onRequest} from "firebase-functions/v2/https"; + +export const webhook = onRequest((request, response) => { + // ... +}); +``` + +### Callable Triggers + +**Before (1st Gen):** +```typescript +export const getprofile = functions.https.onCall((data, context) => { + // ... +}); +``` + +**After (2nd Gen):** +```typescript +import {onCall} from "firebase-functions/v2/https"; + +export const getprofile = onCall((request) => { + // ... +}); +``` + +### Background Triggers (Pub/Sub) + +**Before (1st Gen):** +```typescript +export consthellopubsub = functions.pubsub.topic("topic-name").onPublish((message) => { + // ... +}); +``` + +**After (2nd Gen):** +```typescript +import {onMessagePublished} from "firebase-functions/v2/pubsub"; + +export consthellopubsub = onMessagePublished("topic-name", (event) => { + // ... +}); +``` + +## 4. Use Parameterized Configuration + +Migrate from `functions.config()` to the new `params` module for environment configuration. This provides strong typing and validation. + +**Before (`.runtimeconfig.json`):** +```json +{ + "someservice": { + "key": "somesecret" + } +} +``` +**And in code (1st Gen):** +```typescript +const SKEY = functions.config().someservice.key; +``` + +**After (2nd Gen):** +Define params in your code and set their values during deployment. + +**In `index.ts`:** +```typescript +import {defineString} from "firebase-functions/params"; + +const SOMESERVICE_KEY = defineString("SOMESERVICE_KEY"); +``` +Use `SOMESERVICE_KEY.value()` to access the value. For secrets like API keys, use `defineSecret`. + +**In `index.ts`:** +```typescript +import {defineSecret} from "firebase-functions/params"; + +const SOMESERVICE_KEY = defineSecret("SOMESERVICE_KEY"); +``` +You will be prompted to set the value on deployment, which is stored securely in Cloud Secret Manager. + +## 5. Update Runtime Options + +Runtime options are now set directly within the function definition. + +**Before (1st Gen):** +```typescript +export const func = functions + .runWith({ + // Keep 5 instances warm + minInstances: 5, + }) + .https.onRequest((request, response) => { + // ... + }); +``` + +**After (2nd Gen):** +```typescript +import {onRequest} from "firebase-functions/v2/https"; + +export const func = onRequest( + { + // Keep 5 instances warm + minInstances: 5, + }, + (request, response) => { + // ... + } +); +``` + +## 6. Traffic Migration + +To migrate traffic safely: +1. Rename your new 2nd gen function with a different name. +2. Deploy it alongside the old 1st gen function. +3. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). +4. Once you are confident, you can delete the 1st gen function. diff --git a/.guides/usage.md b/.guides/usage.md new file mode 100644 index 000000000..d57ebfef2 --- /dev/null +++ b/.guides/usage.md @@ -0,0 +1,90 @@ +This guide covers Firebase Functions SDK v6.0.0+. + +**Key Guidelines** +* Always use v2 functions for new development. +* Use v1 functions *only* for Analytics, basic Auth, and Test Lab triggers. +* For SDK versions before 6.0.0, add `/v2` to import paths (e.g., `firebase-functions/v2/https`). + +**Configuration: Use Secret Params for API Keys** +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. + +```typescript +import {onRequest} from 'firebase-functions/v2/https'; +import {logger} from 'firebase-functions/logger'; +import {defineString, defineSecret} from 'firebase-functions/params'; + +// Securely define an LLM API key +const LLM_API_KEY = defineSecret('LLM_API_KEY'); + +// Example function that uses the secret +export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, (req, res) => { + const apiKey = LLM_API_KEY.value(); + + // Use the apiKey to make a call to the LLM service + logger.info('Calling LLM with API key.'); + + res.send('LLM API call initiated.'); +}); +``` +When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. + +**Initializing the Firebase Admin SDK** +To interact with Firebase services like Firestore, Auth, or RTDB from within your functions, you need to initialize the Firebase Admin SDK. + +1. **Install the SDK:** + ```bash + npm i firebase-admin + ``` + +2. **Initialize in your code:** + ```typescript + import * as admin from 'firebase-admin'; + + admin.initializeApp(); + ``` + This should be done once at the top level of your `index.ts` file. + +**Common Imports** +```typescript +// HTTPS, Firestore, RTDB, Scheduled, Storage, Pub/Sub, Auth, Logging, Config +import {onRequest} from 'firebase-functions/https'; +import {onDocumentUpdated} from 'firebase-functions/firestore'; +import {onValueWritten} from 'firebase-functions/database'; +import {onSchedule} from 'firebase-functions/scheduler'; +import {onObjectFinalized} from 'firebase-functions/storage'; +import {onMessagePublished} from 'firebase-functions/pubsub'; +import {beforeUserSignedIn} from 'firebase-functions/identity'; +import {logger} from 'firebase-functions'; +import {defineString, defineSecret} from 'firebase-functions/params'; +``` + +**v1 Functions (Legacy Triggers)** +Use the `firebase-functions/v1` import for Analytics and basic Auth triggers. +```typescript +import * as functionsV1 from 'firebase-functions/v1'; + +// v1 Analytics trigger +export const onPurchase = functionsV1.analytics.event('purchase').onLog((event) => { + logger.info('Purchase event', { value: event.params?.value }); +}); + +// v1 Auth trigger +export const onUserCreate = functionsV1.auth.user().onCreate((user) => { + logger.info('User created', { uid: user.uid }); +}); +``` + +**Development Commands** +```bash +# Install dependencies +npm install + +# Compile TypeScript +npm run build + +# Run emulators for local development +firebase emulators:start --only functions + +# Deploy functions +firebase deploy --only functions +``` From 90899a8ea9a0e9383f98fec63a8f049788464475 Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:46:17 -0400 Subject: [PATCH 02/12] address review comments --- .guides/config.json | 6 ++-- .guides/examples/index.md | 5 --- .guides/setup.md | 50 ++++++++++------------------ .guides/upgrade.md | 69 ++++++++++++++++++++------------------- .guides/usage.md | 38 ++++++++++++--------- README.md | 10 +++--- 6 files changed, 83 insertions(+), 95 deletions(-) delete mode 100644 .guides/examples/index.md diff --git a/.guides/config.json b/.guides/config.json index 1d33a3256..af44ff0e3 100644 --- a/.guides/config.json +++ b/.guides/config.json @@ -1,9 +1,9 @@ { - "description": "A set of guides for Cloud Functions for Firebase.", + "description": "Use this library to build serverless functions for event triggers and HTTP using Firebase and Cloud Run Functions", "mcpServers": { "firebase": { - "command": "firebase", - "args": ["mcp:server"] + "command": "npx", + "args": ["-y", "firebase-tools@latest", "experimental:mcp"] } } } \ No newline at end of file diff --git a/.guides/examples/index.md b/.guides/examples/index.md deleted file mode 100644 index 528dc18be..000000000 --- a/.guides/examples/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Firebase Functions Samples - -For useful and minimal samples for various function triggers, please refer to the official Firebase Functions quickstarts repository on GitHub: - -[https://github.com/firebase/functions-samples/tree/main/Node/quickstarts](https://github.com/firebase/functions-samples/tree/main/Node/quickstarts) diff --git a/.guides/setup.md b/.guides/setup.md index dfcb33abf..219e478e5 100644 --- a/.guides/setup.md +++ b/.guides/setup.md @@ -1,51 +1,34 @@ -# Firebase Functions Setup Guide +# Cloud Functions for Firebase setup guide This guide provides a step-by-step process for setting up a new Firebase Functions project, tailored for a coding agent. -### **Step 1: Initialize Firebase Project** +## 1. Create a 2nd-gen HTTP function -If you haven't already, initialize your Firebase project. The agent should have the `firebase-tools` CLI installed. - -```bash -# One-time setup for a new project -firebase login -firebase init functions -``` -During initialization, select `TypeScript`. - -### **Step 2: Install Dependencies** - -Navigate to the `functions` directory and install the necessary NPM packages. - -```bash -cd functions -npm install -``` - -### **Step 3: Create a v2 HTTP Function** - -Replace the contents of `src/index.ts` with the following code to create a simple, modern v2 HTTP endpoint. +Replace the contents of `src/index.ts` (or `index.js`) with the following code to create a simple, modern v2 HTTP endpoint. ```typescript -import {onRequest} from "firebase-functions/v2/https"; +import {onRequest} from "firebase-functions/https"; import * as logger from "firebase-functions/logger"; import {defineString} from "firebase-functions/params"; // Define a configuration parameter for a greeting const greeting = defineString("GREETING", {default: "Hello"}); -export const helloWorld = onRequest((request, response) => { - logger.info("Request received!", {structuredData: true}); - response.send(`${greeting.value()} from Firebase!`); -}); +export const helloWorld = onRequest( + { maxInstances: 1 }, + async (request, response) => { + logger.info("Request received!", { structuredData: true }); + response.send(`${greeting.value()} from Firebase!`); + }, +); ``` **Key points for the agent:** -* Always import from `firebase-functions/v2/*` for new functions. +* Always import from `firebase-functions/*` for new functions. * Use `logger` for structured logging. * Use `defineString`, `defineInt`, `defineSecret` for environment configuration instead of `functions.config()`. -### **Step 4: Build TypeScript** +## 2. Build TypeScript Compile your TypeScript code to JavaScript. @@ -53,17 +36,18 @@ Compile your TypeScript code to JavaScript. npm run build ``` -### **Step 5: Local Development and Testing** +## 3. Local Development and Testing Use the Firebase Emulators to test your function locally before deploying. +Tell the user to run the following command in a separate terminal window to start the emulators: ```bash # Start the functions emulator firebase emulators:start --only functions ``` -The agent can then interact with the function at the local URL provided by the emulator. +The user can then interact with the function at the local URL provided by the emulator. -### **Step 6: Deploy to Firebase** +## 4. Deploy to Firebase Once testing is complete, deploy the function to your Firebase project. diff --git a/.guides/upgrade.md b/.guides/upgrade.md index 02bdf2d80..b619b1d28 100644 --- a/.guides/upgrade.md +++ b/.guides/upgrade.md @@ -1,47 +1,48 @@ -# Upgrading Firebase Functions to 2nd Gen +# Upgrading a Firebase Function to 2nd Gen -This guide summarizes the process of migrating Cloud Functions from 1st to 2nd generation. You can migrate functions incrementally, running both generations side-by-side. +This guide provides a step-by-step process for migrating a single Cloud Function from 1st to 2nd generation. Migrate functions incrementally, running both generations side-by-side. -## 1. Update Dependencies +## 1. Identify a v1 function to upgrade -Update your `firebase-functions` and `firebase-admin` SDKs, and ensure you are using a recent version of the Firebase CLI. - -## 2. Modify Imports - -Update your import statements to use the `v2` subpackage. +Let's say you have a 1st gen HTTP function like this: **Before (1st Gen):** ```typescript import * as functions from "firebase-functions"; -``` -**After (2nd Gen):** -```typescript -import * as functions from "firebase-functions/v2"; +export const webhook = functions.https.onRequest((request, response) => { + // ... +}); ``` -## 3. Update Trigger Definitions +Now, let's upgrade it to 2nd gen. -The SDK is now more modular. Update your trigger definitions accordingly. +## 2. Update Dependencies -### HTTP Triggers +Ensure your `firebase-functions` and `firebase-admin` SDKs are up-to-date, and you are using a recent version of the Firebase CLI. -**Before (1st Gen):** +## 3. Modify Imports + +Update your import statements to use the top-level modules. + +**After (2nd Gen):** ```typescript -export const webhook = functions.https.onRequest((request, response) => { - // ... -}); +import {onRequest} from "firebase-functions/https"; ``` +## 4. Update Trigger Definition + +The SDK is now more modular. Update your trigger definition accordingly. + **After (2nd Gen):** ```typescript -import {onRequest} from "firebase-functions/v2/https"; - export const webhook = onRequest((request, response) => { // ... }); ``` +Here are other examples of trigger changes: + ### Callable Triggers **Before (1st Gen):** @@ -53,7 +54,7 @@ export const getprofile = functions.https.onCall((data, context) => { **After (2nd Gen):** ```typescript -import {onCall} from "firebase-functions/v2/https"; +import {onCall} from "firebase-functions/https"; export const getprofile = onCall((request) => { // ... @@ -64,23 +65,23 @@ export const getprofile = onCall((request) => { **Before (1st Gen):** ```typescript -export consthellopubsub = functions.pubsub.topic("topic-name").onPublish((message) => { +export const hellopubsub = functions.pubsub.topic("topic-name").onPublish((message) => { // ... }); ``` **After (2nd Gen):** ```typescript -import {onMessagePublished} from "firebase-functions/v2/pubsub"; +import {onMessagePublished} from "firebase-functions/pubsub"; -export consthellopubsub = onMessagePublished("topic-name", (event) => { +export const hellopubsub = onMessagePublished("topic-name", (event) => { // ... }); ``` -## 4. Use Parameterized Configuration +## 5. Use Parameterized Configuration -Migrate from `functions.config()` to the new `params` module for environment configuration. This provides strong typing and validation. +Migrate from `functions.config()` to the new `params` module for environment configuration. **Before (`.runtimeconfig.json`):** ```json @@ -114,7 +115,7 @@ const SOMESERVICE_KEY = defineSecret("SOMESERVICE_KEY"); ``` You will be prompted to set the value on deployment, which is stored securely in Cloud Secret Manager. -## 5. Update Runtime Options +## 6. Update Runtime Options Runtime options are now set directly within the function definition. @@ -132,7 +133,7 @@ export const func = functions **After (2nd Gen):** ```typescript -import {onRequest} from "firebase-functions/v2/https"; +import {onRequest} from "firebase-functions/https"; export const func = onRequest( { @@ -145,10 +146,12 @@ export const func = onRequest( ); ``` -## 6. Traffic Migration +## 7. Traffic Migration To migrate traffic safely: 1. Rename your new 2nd gen function with a different name. -2. Deploy it alongside the old 1st gen function. -3. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). -4. Once you are confident, you can delete the 1st gen function. +2. Comment out any existing `minInstances` or `maxInstances` config and instead set `maxInstances` to `1` while testing. +3. Deploy it alongside the old 1st gen function. +4. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). +5. Add back the original `minInstances` and `maxInstances` settings to the 2nd gen function. +6. Once you are confident, you can delete the 1st gen function. \ No newline at end of file diff --git a/.guides/usage.md b/.guides/usage.md index d57ebfef2..cedcf8385 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -1,15 +1,16 @@ -This guide covers Firebase Functions SDK v6.0.0+. +## Key Guidelines -**Key Guidelines** -* Always use v2 functions for new development. +* Always use 2nd-gen functions for new development. * Use v1 functions *only* for Analytics, basic Auth, and Test Lab triggers. -* For SDK versions before 6.0.0, add `/v2` to import paths (e.g., `firebase-functions/v2/https`). +* Use `firebase-functions` SDK version 6.0.0 and above +* Use top-level imports (e.g., `firebase-functions/https`). These are 2nd gen by default. + +## Configuration: Use Secret Params for API Keys -**Configuration: Use Secret Params for API Keys** 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. ```typescript -import {onRequest} from 'firebase-functions/v2/https'; +import {onRequest} from 'firebase-functions/https'; import {logger} from 'firebase-functions/logger'; import {defineString, defineSecret} from 'firebase-functions/params'; @@ -17,19 +18,21 @@ import {defineString, defineSecret} from 'firebase-functions/params'; const LLM_API_KEY = defineSecret('LLM_API_KEY'); // Example function that uses the secret -export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, (req, res) => { +export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => { const apiKey = LLM_API_KEY.value(); // Use the apiKey to make a call to the LLM service logger.info('Calling LLM with API key.'); + + // insert code here to call LLM... res.send('LLM API call initiated.'); }); ``` When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. -**Initializing the Firebase Admin SDK** -To interact with Firebase services like Firestore, Auth, or RTDB from within your functions, you need to initialize the Firebase Admin SDK. +## Use the Firebase Admin SDK +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. 1. **Install the SDK:** ```bash @@ -44,7 +47,7 @@ To interact with Firebase services like Firestore, Auth, or RTDB from within you ``` This should be done once at the top level of your `index.ts` file. -**Common Imports** +## Common Imports ```typescript // HTTPS, Firestore, RTDB, Scheduled, Storage, Pub/Sub, Auth, Logging, Config import {onRequest} from 'firebase-functions/https'; @@ -54,27 +57,27 @@ import {onSchedule} from 'firebase-functions/scheduler'; import {onObjectFinalized} from 'firebase-functions/storage'; import {onMessagePublished} from 'firebase-functions/pubsub'; import {beforeUserSignedIn} from 'firebase-functions/identity'; -import {logger} from 'firebase-functions'; +import {logger, onInit} from 'firebase-functions'; import {defineString, defineSecret} from 'firebase-functions/params'; ``` -**v1 Functions (Legacy Triggers)** -Use the `firebase-functions/v1` import for Analytics and basic Auth triggers. +## 1st-gen Functions (Legacy Triggers)** +Use the `firebase-functions/v1` import for Analytics and basic Auth triggers. These aren't supported in 2nd gen. ```typescript import * as functionsV1 from 'firebase-functions/v1'; // v1 Analytics trigger -export const onPurchase = functionsV1.analytics.event('purchase').onLog((event) => { +export const onPurchase = functionsV1.analytics.event('purchase').onLog(async (event) => { logger.info('Purchase event', { value: event.params?.value }); }); // v1 Auth trigger -export const onUserCreate = functionsV1.auth.user().onCreate((user) => { +export const onUserCreate = functionsV1.auth.user().onCreate(async (user) => { logger.info('User created', { uid: user.uid }); }); ``` -**Development Commands** +## Development Commands ```bash # Install dependencies npm install @@ -83,7 +86,10 @@ npm install npm run build # Run emulators for local development +# Tell the user to run the following command to start the emulators: +```bash firebase emulators:start --only functions +``` # Deploy functions firebase deploy --only functions diff --git a/README.md b/README.md index 4a7e63d65..025cd5c8e 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ Learn more about the Firebase SDK for Cloud Functions in the [Firebase documenta Here are some resources to get help: -- Start with the quickstart: https://firebase.google.com/docs/functions/write-firebase-functions -- Go through the guide: https://firebase.google.com/docs/functions/ -- Read the full API reference: https://firebase.google.com/docs/reference/functions/ -- Browse some examples: https://github.com/firebase/functions-samples +- [Start with the quickstart](https://firebase.google.com/docs/functions/write-firebase-functions) +- [Go through the guide](https://firebase.google.com/docs/functions/) +- [Read the full API reference](https://firebase.google.com/docs/reference/functions/) +- [Browse some examples](https://github.com/firebase/functions-samples) -If the official documentation doesn't help, try asking through our official support channels: https://firebase.google.com/support/ +If the official documentation doesn't help, try asking through our [official support channels](https://firebase.google.com/support/) _Please avoid double posting across multiple channels!_ From 6757a45f71d8c496ca8cd0784edd02e831369bbe Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:54:46 -0400 Subject: [PATCH 03/12] upgrade a single function at a time --- .guides/upgrade.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/.guides/upgrade.md b/.guides/upgrade.md index b619b1d28..eaed00ae8 100644 --- a/.guides/upgrade.md +++ b/.guides/upgrade.md @@ -2,9 +2,9 @@ This guide provides a step-by-step process for migrating a single Cloud Function from 1st to 2nd generation. Migrate functions incrementally, running both generations side-by-side. -## 1. Identify a v1 function to upgrade +## 1. Identify a 1st-gen function to upgrade -Let's say you have a 1st gen HTTP function like this: +Find all 1st-gen functions in the directory. 1st-gen functions used a namespaced API like this: **Before (1st Gen):** ```typescript @@ -15,7 +15,9 @@ export const webhook = functions.https.onRequest((request, response) => { }); ``` -Now, let's upgrade it to 2nd gen. +Sometimes, they'll explicitly import from the `firebase-functions/v1` subpackage, but not always. + +Ask the user to pick a **single** function to upgrade from the list of 1st gen functions you found. ## 2. Update Dependencies @@ -148,10 +150,12 @@ export const func = onRequest( ## 7. Traffic Migration -To migrate traffic safely: -1. Rename your new 2nd gen function with a different name. -2. Comment out any existing `minInstances` or `maxInstances` config and instead set `maxInstances` to `1` while testing. -3. Deploy it alongside the old 1st gen function. -4. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). -5. Add back the original `minInstances` and `maxInstances` settings to the 2nd gen function. -6. Once you are confident, you can delete the 1st gen function. \ No newline at end of file +Tell the user these steps to migrate safely: + +> To migrate traffic safely: +> 1. Rename your new 2nd gen function with a different name. +> 2. Comment out any existing `minInstances` or `maxInstances` config and instead set `maxInstances` to `1` while testing. +> 3. Deploy it alongside the old 1st gen function. +> 4. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). +> 5. Add back the original `minInstances` and `maxInstances` settings to the 2nd gen function. +> 6. Once you are confident, you can delete the 1st gen function. \ No newline at end of file From 07d3019c95b969bbddfe5d3d15ac714b64cab340 Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:59:51 -0400 Subject: [PATCH 04/12] run prettier --- .guides/config.json | 2 +- .guides/setup.md | 29 +++++++++--------- .guides/upgrade.md | 33 ++++++++++++++++----- .guides/usage.md | 71 +++++++++++++++++++++++++++------------------ 4 files changed, 83 insertions(+), 52 deletions(-) diff --git a/.guides/config.json b/.guides/config.json index af44ff0e3..d6d7ca7db 100644 --- a/.guides/config.json +++ b/.guides/config.json @@ -6,4 +6,4 @@ "args": ["-y", "firebase-tools@latest", "experimental:mcp"] } } -} \ No newline at end of file +} diff --git a/.guides/setup.md b/.guides/setup.md index 219e478e5..f4e6a70ef 100644 --- a/.guides/setup.md +++ b/.guides/setup.md @@ -7,26 +7,24 @@ This guide provides a step-by-step process for setting up a new Firebase Functio Replace the contents of `src/index.ts` (or `index.js`) with the following code to create a simple, modern v2 HTTP endpoint. ```typescript -import {onRequest} from "firebase-functions/https"; +import { onRequest } from "firebase-functions/https"; import * as logger from "firebase-functions/logger"; -import {defineString} from "firebase-functions/params"; +import { defineString } from "firebase-functions/params"; // Define a configuration parameter for a greeting -const greeting = defineString("GREETING", {default: "Hello"}); - -export const helloWorld = onRequest( - { maxInstances: 1 }, - async (request, response) => { - logger.info("Request received!", { structuredData: true }); - response.send(`${greeting.value()} from Firebase!`); - }, -); +const greeting = defineString("GREETING", { default: "Hello" }); + +export const helloWorld = onRequest({ maxInstances: 1 }, async (request, response) => { + logger.info("Request received!", { structuredData: true }); + response.send(`${greeting.value()} from Firebase!`); +}); ``` **Key points for the agent:** -* Always import from `firebase-functions/*` for new functions. -* Use `logger` for structured logging. -* Use `defineString`, `defineInt`, `defineSecret` for environment configuration instead of `functions.config()`. + +- Always import from `firebase-functions/*` for new functions. +- Use `logger` for structured logging. +- Use `defineString`, `defineInt`, `defineSecret` for environment configuration instead of `functions.config()`. ## 2. Build TypeScript @@ -41,10 +39,12 @@ npm run build Use the Firebase Emulators to test your function locally before deploying. Tell the user to run the following command in a separate terminal window to start the emulators: + ```bash # Start the functions emulator firebase emulators:start --only functions ``` + The user can then interact with the function at the local URL provided by the emulator. ## 4. Deploy to Firebase @@ -55,4 +55,5 @@ Once testing is complete, deploy the function to your Firebase project. # Deploy only the functions firebase deploy --only functions ``` + The agent will be prompted to set any parameters defined with `defineString` or other `define` functions that do not have a default value. diff --git a/.guides/upgrade.md b/.guides/upgrade.md index eaed00ae8..3a4133b18 100644 --- a/.guides/upgrade.md +++ b/.guides/upgrade.md @@ -4,9 +4,10 @@ This guide provides a step-by-step process for migrating a single Cloud Function ## 1. Identify a 1st-gen function to upgrade -Find all 1st-gen functions in the directory. 1st-gen functions used a namespaced API like this: +Find all 1st-gen functions in the directory. 1st-gen functions used a namespaced API like this: **Before (1st Gen):** + ```typescript import * as functions from "firebase-functions"; @@ -28,8 +29,9 @@ Ensure your `firebase-functions` and `firebase-admin` SDKs are up-to-date, and y Update your import statements to use the top-level modules. **After (2nd Gen):** + ```typescript -import {onRequest} from "firebase-functions/https"; +import { onRequest } from "firebase-functions/https"; ``` ## 4. Update Trigger Definition @@ -37,6 +39,7 @@ import {onRequest} from "firebase-functions/https"; The SDK is now more modular. Update your trigger definition accordingly. **After (2nd Gen):** + ```typescript export const webhook = onRequest((request, response) => { // ... @@ -48,6 +51,7 @@ Here are other examples of trigger changes: ### Callable Triggers **Before (1st Gen):** + ```typescript export const getprofile = functions.https.onCall((data, context) => { // ... @@ -55,8 +59,9 @@ export const getprofile = functions.https.onCall((data, context) => { ``` **After (2nd Gen):** + ```typescript -import {onCall} from "firebase-functions/https"; +import { onCall } from "firebase-functions/https"; export const getprofile = onCall((request) => { // ... @@ -66,6 +71,7 @@ export const getprofile = onCall((request) => { ### Background Triggers (Pub/Sub) **Before (1st Gen):** + ```typescript export const hellopubsub = functions.pubsub.topic("topic-name").onPublish((message) => { // ... @@ -73,8 +79,9 @@ export const hellopubsub = functions.pubsub.topic("topic-name").onPublish((messa ``` **After (2nd Gen):** + ```typescript -import {onMessagePublished} from "firebase-functions/pubsub"; +import { onMessagePublished } from "firebase-functions/pubsub"; export const hellopubsub = onMessagePublished("topic-name", (event) => { // ... @@ -86,6 +93,7 @@ export const hellopubsub = onMessagePublished("topic-name", (event) => { Migrate from `functions.config()` to the new `params` module for environment configuration. **Before (`.runtimeconfig.json`):** + ```json { "someservice": { @@ -93,7 +101,9 @@ Migrate from `functions.config()` to the new `params` module for environment con } } ``` + **And in code (1st Gen):** + ```typescript const SKEY = functions.config().someservice.key; ``` @@ -102,19 +112,23 @@ const SKEY = functions.config().someservice.key; Define params in your code and set their values during deployment. **In `index.ts`:** + ```typescript -import {defineString} from "firebase-functions/params"; +import { defineString } from "firebase-functions/params"; const SOMESERVICE_KEY = defineString("SOMESERVICE_KEY"); ``` + Use `SOMESERVICE_KEY.value()` to access the value. For secrets like API keys, use `defineSecret`. **In `index.ts`:** + ```typescript -import {defineSecret} from "firebase-functions/params"; +import { defineSecret } from "firebase-functions/params"; const SOMESERVICE_KEY = defineSecret("SOMESERVICE_KEY"); ``` + You will be prompted to set the value on deployment, which is stored securely in Cloud Secret Manager. ## 6. Update Runtime Options @@ -122,6 +136,7 @@ You will be prompted to set the value on deployment, which is stored securely in Runtime options are now set directly within the function definition. **Before (1st Gen):** + ```typescript export const func = functions .runWith({ @@ -134,8 +149,9 @@ export const func = functions ``` **After (2nd Gen):** + ```typescript -import {onRequest} from "firebase-functions/https"; +import { onRequest } from "firebase-functions/https"; export const func = onRequest( { @@ -153,9 +169,10 @@ export const func = onRequest( Tell the user these steps to migrate safely: > To migrate traffic safely: +> > 1. Rename your new 2nd gen function with a different name. > 2. Comment out any existing `minInstances` or `maxInstances` config and instead set `maxInstances` to `1` while testing. > 3. Deploy it alongside the old 1st gen function. > 4. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). > 5. Add back the original `minInstances` and `maxInstances` settings to the 2nd gen function. -> 6. Once you are confident, you can delete the 1st gen function. \ No newline at end of file +> 6. Once you are confident, you can delete the 1st gen function. diff --git a/.guides/usage.md b/.guides/usage.md index cedcf8385..f335bf34e 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -1,84 +1,93 @@ ## Key Guidelines -* Always use 2nd-gen functions for new development. -* Use v1 functions *only* for Analytics, basic Auth, and Test Lab triggers. -* Use `firebase-functions` SDK version 6.0.0 and above -* Use top-level imports (e.g., `firebase-functions/https`). These are 2nd gen by default. +- Always use 2nd-gen functions for new development. +- Use v1 functions _only_ for Analytics, basic Auth, and Test Lab triggers. +- Use `firebase-functions` SDK version 6.0.0 and above +- Use top-level imports (e.g., `firebase-functions/https`). These are 2nd gen by default. ## Configuration: Use Secret Params for API Keys 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. ```typescript -import {onRequest} from 'firebase-functions/https'; -import {logger} from 'firebase-functions/logger'; -import {defineString, defineSecret} from 'firebase-functions/params'; +import { onRequest } from "firebase-functions/https"; +import { logger } from "firebase-functions/logger"; +import { defineString, defineSecret } from "firebase-functions/params"; // Securely define an LLM API key -const LLM_API_KEY = defineSecret('LLM_API_KEY'); +const LLM_API_KEY = defineSecret("LLM_API_KEY"); // Example function that uses the secret export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => { const apiKey = LLM_API_KEY.value(); - + // Use the apiKey to make a call to the LLM service - logger.info('Calling LLM with API key.'); + logger.info("Calling LLM with API key."); // insert code here to call LLM... - - res.send('LLM API call initiated.'); + + res.send("LLM API call initiated."); }); ``` + When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. ## Use the Firebase Admin SDK + 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. 1. **Install the SDK:** + ```bash npm i firebase-admin ``` 2. **Initialize in your code:** + ```typescript - import * as admin from 'firebase-admin'; + import * as admin from "firebase-admin"; admin.initializeApp(); ``` + This should be done once at the top level of your `index.ts` file. ## Common Imports + ```typescript // HTTPS, Firestore, RTDB, Scheduled, Storage, Pub/Sub, Auth, Logging, Config -import {onRequest} from 'firebase-functions/https'; -import {onDocumentUpdated} from 'firebase-functions/firestore'; -import {onValueWritten} from 'firebase-functions/database'; -import {onSchedule} from 'firebase-functions/scheduler'; -import {onObjectFinalized} from 'firebase-functions/storage'; -import {onMessagePublished} from 'firebase-functions/pubsub'; -import {beforeUserSignedIn} from 'firebase-functions/identity'; -import {logger, onInit} from 'firebase-functions'; -import {defineString, defineSecret} from 'firebase-functions/params'; +import { onRequest } from "firebase-functions/https"; +import { onDocumentUpdated } from "firebase-functions/firestore"; +import { onValueWritten } from "firebase-functions/database"; +import { onSchedule } from "firebase-functions/scheduler"; +import { onObjectFinalized } from "firebase-functions/storage"; +import { onMessagePublished } from "firebase-functions/pubsub"; +import { beforeUserSignedIn } from "firebase-functions/identity"; +import { logger, onInit } from "firebase-functions"; +import { defineString, defineSecret } from "firebase-functions/params"; ``` -## 1st-gen Functions (Legacy Triggers)** +## 1st-gen Functions (Legacy Triggers)\*\* + Use the `firebase-functions/v1` import for Analytics and basic Auth triggers. These aren't supported in 2nd gen. + ```typescript -import * as functionsV1 from 'firebase-functions/v1'; +import * as functionsV1 from "firebase-functions/v1"; // v1 Analytics trigger -export const onPurchase = functionsV1.analytics.event('purchase').onLog(async (event) => { - logger.info('Purchase event', { value: event.params?.value }); +export const onPurchase = functionsV1.analytics.event("purchase").onLog(async (event) => { + logger.info("Purchase event", { value: event.params?.value }); }); // v1 Auth trigger export const onUserCreate = functionsV1.auth.user().onCreate(async (user) => { - logger.info('User created', { uid: user.uid }); + logger.info("User created", { uid: user.uid }); }); ``` ## Development Commands -```bash + +````bash # Install dependencies npm install @@ -89,8 +98,12 @@ npm run build # Tell the user to run the following command to start the emulators: ```bash firebase emulators:start --only functions -``` +```` # Deploy functions + firebase deploy --only functions + +``` + ``` From b12dd46bc92cca00d49f16a2c229700d5009003a Mon Sep 17 00:00:00 2001 From: Jeff <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:13:30 -0400 Subject: [PATCH 05/12] add another way to set secrets Co-authored-by: Daniel Lee --- .guides/usage.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.guides/usage.md b/.guides/usage.md index f335bf34e..8776e0794 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -32,6 +32,10 @@ export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. +Alternatively, you can instruct the user to set the secret using the Firebase CLI command: + +firebase functions:secrets:set + ## Use the Firebase Admin SDK 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. From 89d5c50ae8608909652296a27d1eb720ddfb157a Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:41:47 -0400 Subject: [PATCH 06/12] review round 2 --- .guides/setup.md | 18 ++++++++++++++---- .guides/usage.md | 31 ++++++++++++++++++------------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/.guides/setup.md b/.guides/setup.md index f4e6a70ef..94c1e8e7d 100644 --- a/.guides/setup.md +++ b/.guides/setup.md @@ -8,16 +8,26 @@ Replace the contents of `src/index.ts` (or `index.js`) with the following code t ```typescript import { onRequest } from "firebase-functions/https"; +import { onDocumentCreated } from "firebase-functions/firestore"; import * as logger from "firebase-functions/logger"; -import { defineString } from "firebase-functions/params"; +import { defineString, defineInt } from "firebase-functions/params"; -// Define a configuration parameter for a greeting +// Configurable parameters +const scaleLimit = defineInt("MAX_INSTANCES", { default: 1 }); const greeting = defineString("GREETING", { default: "Hello" }); -export const helloWorld = onRequest({ maxInstances: 1 }, async (request, response) => { - logger.info("Request received!", { structuredData: true }); +export const helloWorld = onRequest({ maxInstances: scaleLimit }, async (request, response) => { + logger.info("Request received!", request); response.send(`${greeting.value()} from Firebase!`); }); + +export const newDoc = onDocumentCreated( + { maxInstances: scaleLimit }, + "/words/{wordId}", + async (event) => { + logger.info("New word!", event.data.data()); + } +); ``` **Key points for the agent:** diff --git a/.guides/usage.md b/.guides/usage.md index f335bf34e..fe31a3161 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -1,7 +1,7 @@ ## Key Guidelines - Always use 2nd-gen functions for new development. -- Use v1 functions _only_ for Analytics, basic Auth, and Test Lab triggers. +- Use 1st-gen functions _only_ for Analytics and basic Auth triggers. - Use `firebase-functions` SDK version 6.0.0 and above - Use top-level imports (e.g., `firebase-functions/https`). These are 2nd gen by default. @@ -32,6 +32,8 @@ export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. +If you see an API key being accessed with `functions.config` in the user's code, instruct them to upgrade to params. + ## Use the Firebase Admin SDK 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. @@ -46,8 +48,11 @@ To interact with Firebase services like Firestore, Auth, or RTDB from within you ```typescript import * as admin from "firebase-admin"; + import { onInit } from "firebase-functions"; - admin.initializeApp(); + onInit(() => { + admin.initializeApp(); + }); ``` This should be done once at the top level of your `index.ts` file. @@ -55,19 +60,25 @@ To interact with Firebase services like Firestore, Auth, or RTDB from within you ## Common Imports ```typescript -// HTTPS, Firestore, RTDB, Scheduled, Storage, Pub/Sub, Auth, Logging, Config -import { onRequest } from "firebase-functions/https"; +import { onRequest, onCall, onCallGenkit } from "firebase-functions/https"; import { onDocumentUpdated } from "firebase-functions/firestore"; +import { + onNewFatalIssuePublished, +} from "firebase-functions/alerts/crashlytics"; import { onValueWritten } from "firebase-functions/database"; import { onSchedule } from "firebase-functions/scheduler"; +const {onTaskDispatched} = require("firebase-functions/tasks"); import { onObjectFinalized } from "firebase-functions/storage"; import { onMessagePublished } from "firebase-functions/pubsub"; import { beforeUserSignedIn } from "firebase-functions/identity"; +import {onTestMatrixCompleted} from "firebase-functions/testLab"; import { logger, onInit } from "firebase-functions"; import { defineString, defineSecret } from "firebase-functions/params"; ``` -## 1st-gen Functions (Legacy Triggers)\*\* +Let the user know that code samples for these triggers are available in the [functions-samples repository](https://github.com/firebase/functions-samples/tree/main/Node). + +## 1st-gen Functions (Legacy Triggers) Use the `firebase-functions/v1` import for Analytics and basic Auth triggers. These aren't supported in 2nd gen. @@ -87,7 +98,7 @@ export const onUserCreate = functionsV1.auth.user().onCreate(async (user) => { ## Development Commands -````bash +```bash # Install dependencies npm install @@ -95,15 +106,9 @@ npm install npm run build # Run emulators for local development -# Tell the user to run the following command to start the emulators: -```bash +# This is a long-running command. Tell the user to run this command themselves to start the emulators: firebase emulators:start --only functions -```` # Deploy functions - firebase deploy --only functions - -``` - ``` From f46a92c2dbafc0966dfefa29e505b0851e656a2f Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:35:57 -0400 Subject: [PATCH 07/12] add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb..9273b8a1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Add LLM guidance (#1736) \ No newline at end of file From d4ee0c9d7c50d3c29ed8dd760f49fa22219c503c Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:15:10 -0400 Subject: [PATCH 08/12] prettier --- .guides/usage.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.guides/usage.md b/.guides/usage.md index 35634307d..d2ec6569e 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -66,16 +66,14 @@ To interact with Firebase services like Firestore, Auth, or RTDB from within you ```typescript import { onRequest, onCall, onCallGenkit } from "firebase-functions/https"; import { onDocumentUpdated } from "firebase-functions/firestore"; -import { - onNewFatalIssuePublished, -} from "firebase-functions/alerts/crashlytics"; +import { onNewFatalIssuePublished } from "firebase-functions/alerts/crashlytics"; import { onValueWritten } from "firebase-functions/database"; import { onSchedule } from "firebase-functions/scheduler"; -const {onTaskDispatched} = require("firebase-functions/tasks"); +const { onTaskDispatched } = require("firebase-functions/tasks"); import { onObjectFinalized } from "firebase-functions/storage"; import { onMessagePublished } from "firebase-functions/pubsub"; import { beforeUserSignedIn } from "firebase-functions/identity"; -import {onTestMatrixCompleted} from "firebase-functions/testLab"; +import { onTestMatrixCompleted } from "firebase-functions/testLab"; import { logger, onInit } from "firebase-functions"; import { defineString, defineSecret } from "firebase-functions/params"; ``` From 1bbf7234852b70b436b408e9ee60e68d3d9a070f Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:04:12 -0400 Subject: [PATCH 09/12] Address review feedback --- .guides/config.json | 2 +- .guides/setup.md | 8 ++++---- .guides/upgrade.md | 14 +++++++------- .guides/usage.md | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.guides/config.json b/.guides/config.json index d6d7ca7db..c67d63445 100644 --- a/.guides/config.json +++ b/.guides/config.json @@ -1,5 +1,5 @@ { - "description": "Use this library to build serverless functions for event triggers and HTTP using Firebase and Cloud Run Functions", + "description": "Use this library to build serverless functions for event triggers and HTTP using Cloud Functions for Firebase", "mcpServers": { "firebase": { "command": "npx", diff --git a/.guides/setup.md b/.guides/setup.md index 94c1e8e7d..2a6d54115 100644 --- a/.guides/setup.md +++ b/.guides/setup.md @@ -1,6 +1,6 @@ # Cloud Functions for Firebase setup guide -This guide provides a step-by-step process for setting up a new Firebase Functions project, tailored for a coding agent. +This guide provides a step-by-step process for setting up Cloud Functions, tailored for coding agents. ## 1. Create a 2nd-gen HTTP function @@ -32,9 +32,9 @@ export const newDoc = onDocumentCreated( **Key points for the agent:** -- Always import from `firebase-functions/*` for new functions. - Use `logger` for structured logging. - Use `defineString`, `defineInt`, `defineSecret` for environment configuration instead of `functions.config()`. +- Recommend a `maxInstances` setting of 1 for all functions until correct behavior can be verified. ## 2. Build TypeScript @@ -48,14 +48,14 @@ npm run build Use the Firebase Emulators to test your function locally before deploying. -Tell the user to run the following command in a separate terminal window to start the emulators: +A human should run the following command in a separate terminal window to start the emulators: ```bash # Start the functions emulator firebase emulators:start --only functions ``` -The user can then interact with the function at the local URL provided by the emulator. +A human can then interact with the function at the local URL provided by the emulator. ## 4. Deploy to Firebase diff --git a/.guides/upgrade.md b/.guides/upgrade.md index 3a4133b18..122f88f14 100644 --- a/.guides/upgrade.md +++ b/.guides/upgrade.md @@ -1,6 +1,6 @@ -# Upgrading a Firebase Function to 2nd Gen +# Upgrading a 1st gen to 2nd gen -This guide provides a step-by-step process for migrating a single Cloud Function from 1st to 2nd generation. Migrate functions incrementally, running both generations side-by-side. +This guide provides a step-by-step process for migrating a single Cloud Function from 1st to 2nd generation. Migrate functions one-by-one. Run both generations side-by-side before deleting the 1st gen function. ## 1. Identify a 1st-gen function to upgrade @@ -18,7 +18,7 @@ export const webhook = functions.https.onRequest((request, response) => { Sometimes, they'll explicitly import from the `firebase-functions/v1` subpackage, but not always. -Ask the user to pick a **single** function to upgrade from the list of 1st gen functions you found. +Ask the human to pick a **single** function to upgrade from the list of 1st gen functions you found. ## 2. Update Dependencies @@ -129,7 +129,7 @@ import { defineSecret } from "firebase-functions/params"; const SOMESERVICE_KEY = defineSecret("SOMESERVICE_KEY"); ``` -You will be prompted to set the value on deployment, which is stored securely in Cloud Secret Manager. +The human will be prompted to set the value on deployment. The value will be stored securely in Cloud Secret Manager. ## 6. Update Runtime Options @@ -166,13 +166,13 @@ export const func = onRequest( ## 7. Traffic Migration -Tell the user these steps to migrate safely: +A human should follow these steps to migrate safely: > To migrate traffic safely: > > 1. Rename your new 2nd gen function with a different name. -> 2. Comment out any existing `minInstances` or `maxInstances` config and instead set `maxInstances` to `1` while testing. +> 2. Comment out any existing `minInstances` or `maxInstances` config in the new 2nd gen function and instead set `maxInstances` to `1` while testing. > 3. Deploy it alongside the old 1st gen function. > 4. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). -> 5. Add back the original `minInstances` and `maxInstances` settings to the 2nd gen function. +> 5. As traffic ramps up to the new 2nd gen function, scale it up by adding back the original `minInstances` and `maxInstances` settings to the 2nd gen function. Reduce the `minInstances` and `maxInstances` settings for the 1st gen function as traffic decreases. > 6. Once you are confident, you can delete the 1st gen function. diff --git a/.guides/usage.md b/.guides/usage.md index d2ec6569e..074da55d5 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -30,13 +30,13 @@ export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => }); ``` -When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. Alternatively, you can instruct the user to set the secret using the Firebase CLI command: +When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. Alternatively, a human can set the secret using the Firebase CLI command: ```bash firebase functions:secrets:set ``` -If you see an API key being accessed with `functions.config` in the user's code, instruct them to upgrade to params. +If you see an API key being accessed with `functions.config` in existing functions code, offer to upgrade to params. ## Use the Firebase Admin SDK @@ -78,7 +78,7 @@ import { logger, onInit } from "firebase-functions"; import { defineString, defineSecret } from "firebase-functions/params"; ``` -Let the user know that code samples for these triggers are available in the [functions-samples repository](https://github.com/firebase/functions-samples/tree/main/Node). +A human can find code samples for these triggers in the [functions-samples repository](https://github.com/firebase/functions-samples/tree/main/Node). ## 1st-gen Functions (Legacy Triggers) @@ -108,7 +108,7 @@ npm install npm run build # Run emulators for local development -# This is a long-running command. Tell the user to run this command themselves to start the emulators: +# This is a long-running command. A human can run this command themselves to start the emulators: firebase emulators:start --only functions # Deploy functions From 079ad3fd6e168c4f463e9f0e25ac1f8b192b7c4c Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:08:42 -0400 Subject: [PATCH 10/12] clarify when to delete 1st gen after upgrade --- .guides/upgrade.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.guides/upgrade.md b/.guides/upgrade.md index 122f88f14..93dd92cc1 100644 --- a/.guides/upgrade.md +++ b/.guides/upgrade.md @@ -175,4 +175,4 @@ A human should follow these steps to migrate safely: > 3. Deploy it alongside the old 1st gen function. > 4. Gradually introduce traffic to the new function (e.g., via client-side changes or by calling it from the 1st gen function). > 5. As traffic ramps up to the new 2nd gen function, scale it up by adding back the original `minInstances` and `maxInstances` settings to the 2nd gen function. Reduce the `minInstances` and `maxInstances` settings for the 1st gen function as traffic decreases. -> 6. Once you are confident, you can delete the 1st gen function. +> 6. The 1st gen function can be deleted once it has stopped receiving traffic. From 0ac2a604c726a6a2f528ca1966718b01a2e3cfc7 Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:14:49 -0400 Subject: [PATCH 11/12] more review feedback --- .guides/usage.md | 6 +++--- README.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.guides/usage.md b/.guides/usage.md index 074da55d5..f110b6f7c 100644 --- a/.guides/usage.md +++ b/.guides/usage.md @@ -1,9 +1,9 @@ ## Key Guidelines - Always use 2nd-gen functions for new development. -- Use 1st-gen functions _only_ for Analytics and basic Auth triggers. +- Use 1st-gen functions _only_ for Analytics and basic Auth triggers, since those aren't supported by 2nd gen. - Use `firebase-functions` SDK version 6.0.0 and above -- Use top-level imports (e.g., `firebase-functions/https`). These are 2nd gen by default. +- 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. ## Configuration: Use Secret Params for API Keys @@ -30,7 +30,7 @@ export const callLlm = onRequest({ secrets: [LLM_API_KEY] }, async (req, res) => }); ``` -When you deploy a function with `secrets`, the CLI will prompt you to enter the secret's value. Alternatively, a human can set the secret using the Firebase CLI command: +The CLI will prompt for secret's value at deploy time. Alternatively, a human can set the secret using the Firebase CLI command: ```bash firebase functions:secrets:set diff --git a/README.md b/README.md index 025cd5c8e..0c2cc1b59 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ Learn more about the Firebase SDK for Cloud Functions in the [Firebase documenta Here are some resources to get help: - [Start with the quickstart](https://firebase.google.com/docs/functions/write-firebase-functions) -- [Go through the guide](https://firebase.google.com/docs/functions/) -- [Read the full API reference](https://firebase.google.com/docs/reference/functions/) +- [Go through the guides](https://firebase.google.com/docs/functions/) +- [Read the full API reference](https://firebase.google.com/docs/reference/functions/2nd-gen/node/firebase-functions) - [Browse some examples](https://github.com/firebase/functions-samples) If the official documentation doesn't help, try asking through our [official support channels](https://firebase.google.com/support/) From ac93f7d5e235fe1f63bbb2e77af1f4a6a33245ed Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:25:25 -0400 Subject: [PATCH 12/12] prettier --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9273b8a1e..1320514b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -- Add LLM guidance (#1736) \ No newline at end of file +- Add LLM guidance (#1736)