Loading the skills library…

Skill for converting an installed Firebase Extension (or extension source) into a standalone Cloud Functions for Firebase codebase or publishable npm package, including V1 to V2 trigger upgrades, lifecycle hooks, and declarative security
npx skills add firebase/agent-skills --skill extension-to-functions-codebaseInstalls from the source repository, including any supporting files.
Downloads contain the instructions shown here. Use the install command for the complete skill.
Migrates a Firebase Extension into either:
functions/src/ for app integration).Leverages native Cloud Functions features (declarative IAM, Parameterized Config, SDK Lifecycle Hooks) and modernizes 1st Gen triggers to 2nd Gen using the Destructuring Compatibility Shim.
Target A: Local Functions Codebase (End-User App Integration)
functions/src/. Config in .env.firebase deploy --only functions.Target B: Publishable npm Package / Shareable Package
package.json specifying exports map,
engines: { "node": ">=22" }, and
peerDependencies: { "firebase-functions": ">=6.0.0" }.index.ts
(export * from "<package-name>").Use native SDK declarations instead of manual gcloud scripts or console
instructions:
requiresRole("roles/...") for required GCP IAM permissions.requiresAPI("service.googleapis.com", "Description") for Google APIs..value() at top-level module load scope.onInit() or lazy getters:
import { defineString } from "firebase-functions/params";
import { onInit } from "firebase-functions/v2";
const dataset = defineString("DATASET_ID");
let client: BigQuery;
onInit(() => {
client = new BigQuery({ datasetId: dataset.value() });
});
V2 enables concurrency (up to 80 requests). To preserve V1 single-concurrency
pricing, set cpu: "gcf_gen1".
extension.yaml:
params → defineString, defineInt, defineBoolean, defineSecret.apis → requiresAPI(...).roles → requiresRole(...).lifecycleEvents → afterFirstDeploy & afterRedeploy.resources → Upgrade 1st Gen triggers to 2nd Gen (onDocumentWritten,
onTaskDispatched, onRequest).jest), and
test scripts.package.jsonname: "<package-name>", engines: { "node": ">=22" }.peerDependencies:
"peerDependencies": {
"firebase-admin": "^11.0.0 || ^12.0.0",
"firebase-functions": ">=6.0.0"
}
exports map targeting ESM/CommonJS and TypeScript declarations
(lib/index.js, lib/index.d.ts).onDocumentWritten from firebase-functions/v2/firestore.onTaskDispatched from firebase-functions/v2/tasks. Remove
EXT_INSTANCE_ID when enqueueing tasks.onRequest from firebase-functions/v2/https.{ change, context },
{ snapshot, context }) where legacy 1st Gen handlers expect
(change, context).Map extension lifecycle events to SDK lifecycle hooks in src/index.ts:
onInstall → afterFirstDeploy({ task: { function: "initTask" } })onUpdate / onConfigure →
afterRedeploy({ task: { function: "setupTask" } })Generate README.md containing:
npm install).export * from "<package-name>")..env reference table.Reminder: NEVER execute npm publish.
---
name: extension-to-functions-codebase
description: Skill for converting an installed Firebase Extension (or extension source) into a standalone Cloud Functions for Firebase codebase or publishable npm package, including V1 to V2 trigger upgrades, lifecycle hooks, and declarative security
metadata:
author: Google LLC
category: Serverless
---
# Extension to Functions Codebase & npm Package Migration
## Overview
Migrates a Firebase Extension into either:
1. **A local Cloud Functions codebase** (`functions/src/` for app integration).
1. **A publishable npm package** (reusable open-source package exporting V2
functions).
Leverages native Cloud Functions features (declarative IAM, Parameterized
Config, SDK Lifecycle Hooks) and modernizes 1st Gen triggers to 2nd Gen using
the Destructuring Compatibility Shim.
______________________________________________________________________
## Target Migration Workflows
- **Target A: Local Functions Codebase** (End-User App Integration)
- Output: Code under `functions/src/`. Config in `.env`.
- Deployment: `firebase deploy --only functions`.
- **Target B: Publishable npm Package / Shareable Package**
- Output: Reusable npm package exporting V2 functions.
- Configuration: `package.json` specifying `exports` map,
`engines: { "node": ">=22" }`, and
`peerDependencies: { "firebase-functions": ">=6.0.0" }`.
- Usage: Consumers install package and re-export functions in `index.ts`
(`export * from "<package-name>"`).
______________________________________________________________________
## Core Rules & Constraints
### 1. Declarative IAM & APIs (Zero-Local-Overhead)
Use native SDK declarations instead of manual `gcloud` scripts or console
instructions:
- Use `requiresRole("roles/...")` for required GCP IAM permissions.
- Use `requiresAPI("service.googleapis.com", "Description")` for Google APIs.
### 2. Global Parameter Access Restriction
- **Never call `.value()` at top-level module load scope.**
- Initialize global SDK instances inside `onInit()` or lazy getters:
```typescript
import { defineString } from "firebase-functions/params";
import { onInit } from "firebase-functions/v2";
const dataset = defineString("DATASET_ID");
let client: BigQuery;
onInit(() => {
client = new BigQuery({ datasetId: dataset.value() });
});
```
### 3. V2 Concurrency & Cost Parity
V2 enables concurrency (up to 80 requests). To preserve V1 single-concurrency
pricing, set `cpu: "gcf_gen1"`.
______________________________________________________________________
## Step-by-Step Migration Execution
### Step 1: Inventory Extension Resources
1. **`extension.yaml`**:
- `params` → `defineString`, `defineInt`, `defineBoolean`, `defineSecret`.
- `apis` → `requiresAPI(...)`.
- `roles` → `requiresRole(...)`.
- `lifecycleEvents` → `afterFirstDeploy` & `afterRedeploy`.
- `resources` → Upgrade 1st Gen triggers to 2nd Gen (`onDocumentWritten`,
`onTaskDispatched`, `onRequest`).
1. **Files & Scripts**: Preserve devDependencies, test framework (`jest`), and
test scripts.
### Step 2: Configure `package.json`
- Set `name: "<package-name>"`, `engines: { "node": ">=22" }`.
- Set `peerDependencies`:
```json
"peerDependencies": {
"firebase-admin": "^11.0.0 || ^12.0.0",
"firebase-functions": ">=6.0.0"
}
```
- Configure `exports` map targeting ESM/CommonJS and TypeScript declarations
(`lib/index.js`, `lib/index.d.ts`).
### Step 3: Upgrade Triggers from V1 to V2
- Firestore: Use `onDocumentWritten` from `firebase-functions/v2/firestore`.
- Tasks: Use `onTaskDispatched` from `firebase-functions/v2/tasks`. Remove
`EXT_INSTANCE_ID` when enqueueing tasks.
- HTTP: Use `onRequest` from `firebase-functions/v2/https`.
- Apply Destructuring Compatibility Shim (`{ change, context }`,
`{ snapshot, context }`) where legacy 1st Gen handlers expect
`(change, context)`.
### Step 4: Convert Lifecycle Events
Map extension lifecycle events to SDK lifecycle hooks in `src/index.ts`:
- `onInstall` → `afterFirstDeploy({ task: { function: "initTask" } })`
- `onUpdate` / `onConfigure` →
`afterRedeploy({ task: { function: "setupTask" } })`
### Step 5: Package README & Export Instructions
Generate `README.md` containing:
1. Installation instructions (`npm install`).
1. Re-export snippet (`export * from "<package-name>"`).
1. Parameterized Configuration `.env` reference table.
1. What Changed (Extension vs Package) comparison table.
_Reminder: NEVER execute `npm publish`._