Skip to content
9 changes: 9 additions & 0 deletions .guides/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"description": "Use this library to build serverless functions for event triggers and HTTP using Cloud Functions for Firebase",
"mcpServers": {
"firebase": {
"command": "npx",
"args": ["-y", "firebase-tools@latest", "experimental:mcp"]
}
}
}
69 changes: 69 additions & 0 deletions .guides/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Cloud Functions for Firebase setup guide

This guide provides a step-by-step process for setting up Cloud Functions, tailored for coding agents.

## 1. Create a 2nd-gen HTTP function

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 { onDocumentCreated } from "firebase-functions/firestore";
import * as logger from "firebase-functions/logger";
import { defineString, defineInt } from "firebase-functions/params";

// Configurable parameters
const scaleLimit = defineInt("MAX_INSTANCES", { default: 1 });
const greeting = defineString("GREETING", { default: "Hello" });

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:**

- 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

Compile your TypeScript code to JavaScript.

```bash
npm run build
```

## 3. Local Development and Testing

Use the Firebase Emulators to test your function locally before deploying.

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
```

A human can then interact with the function at the local URL provided by the emulator.

## 4. 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.
178 changes: 178 additions & 0 deletions .guides/upgrade.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be really powerful, but we need to be careful. Maybe the goal of /upgrade should be to upgrade a single function at a time and the guide should be written in that way - like step 1 find v1 functions step 2 ask user which function to upgrade and then it has the guidance to do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that does sound safer. I've changed step 1 to find and prompt for a single function to migrate.

Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# 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 one-by-one. Run both generations side-by-side before deleting the 1st gen 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:

**Before (1st Gen):**

```typescript
import * as functions from "firebase-functions";

export const webhook = functions.https.onRequest((request, response) => {
// ...
});
```

Sometimes, they'll explicitly import from the `firebase-functions/v1` subpackage, but not always.
Comment on lines +7 to +19
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@taeold this seems like a cool opportunity for an mcp tool

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MCP tools for something very niche like "find all v1 functions" are a bit of a tough sell for me, but what you can do is pre-specify shell commands that will get the info you want. For example a find or grep or sed command that helps it find all the files it needs to look at.


Ask the human to pick a **single** function to upgrade from the list of 1st gen functions you found.

## 2. Update Dependencies

Ensure your `firebase-functions` and `firebase-admin` SDKs are up-to-date, and you are using a recent version of the Firebase CLI.

## 3. Modify Imports

Update your import statements to use the top-level modules.

**After (2nd Gen):**

```typescript
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
export const webhook = onRequest((request, response) => {
// ...
});
```

Here are other examples of trigger changes:

### Callable Triggers

**Before (1st Gen):**

```typescript
export const getprofile = functions.https.onCall((data, context) => {
// ...
});
```

**After (2nd Gen):**

```typescript
import { onCall } from "firebase-functions/https";

export const getprofile = onCall((request) => {
// ...
});
```

### Background Triggers (Pub/Sub)

**Before (1st Gen):**

```typescript
export const hellopubsub = functions.pubsub.topic("topic-name").onPublish((message) => {
// ...
});
```

**After (2nd Gen):**

```typescript
import { onMessagePublished } from "firebase-functions/pubsub";

export const hellopubsub = onMessagePublished("topic-name", (event) => {
// ...
});
```

## 5. Use Parameterized Configuration

Migrate from `functions.config()` to the new `params` module for environment configuration.

**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");
```

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

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/https";

export const func = onRequest(
{
// Keep 5 instances warm
minInstances: 5,
},
(request, response) => {
// ...
}
);
```

## 7. Traffic Migration

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 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. 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. The 1st gen function can be deleted once it has stopped receiving traffic.
116 changes: 116 additions & 0 deletions .guides/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
## Key Guidelines

- Always use 2nd-gen functions for new development.
- 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. 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

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";

// 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] }, 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.");
});
```

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 <SECRET_NAME>
```

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

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 { onInit } from "firebase-functions";

onInit(() => {
admin.initializeApp();
});
```

This should be done once at the top level of your `index.ts` file.

## Common Imports

```typescript
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";
```

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)

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(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 });
});
```

## Development Commands

```bash
# Install dependencies
npm install

# Compile TypeScript
npm run build

# Run emulators for local development
# This is a long-running command. A human can run this command themselves to start the emulators:
firebase emulators:start --only functions

# Deploy functions
firebase deploy --only functions
```
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add LLM guidance (#1736)
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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/
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!_

Expand Down
Loading