Apps using 1st gen functions should consider migrating to 2nd gen
using the instructions in this guide. 2nd gen functions use Cloud Run to provide
better performance, better configuration, better monitoring, and more.

> [!NOTE]
> **Note:** Cloud Functions for Firebase (2nd gen) also provides Python support. You can [get started](https://firebase.google.com/docs/functions/get-started.md.txt) with Python using our basic tutorial's snippets and instructions.

The examples in this document assume you're using JavaScript with CommonJS
modules
(`require` style imports), but the same principles apply to JavaScript with ESM
(`import ... from` style imports) and TypeScript.

## The migration process

1st gen and 2nd gen functions can coexist side-by-side in the same source file.
This lets you migrate your codebase piece by piece, as you're ready. Note,
however, that this mixing of packages does *not* work within a single, discrete
*function*.

We recommend migrating one function at a time, performing testing and
verification before proceeding.

## Verify Firebase CLI and `firebase-functions` versions

Make sure you're using at least Firebase CLI version `12.00` and
`firebase-functions` version `4.3.0`. Any newer version will support 2nd gen as
well as 1st gen.

## Update imports

2nd gen functions import from the `v2` subpackage in the `firebase-functions`
SDK. This different import path is all the Firebase CLI needs to determine
whether to deploy your function code as a 1st or 2nd gen function.

The `v2` subpackage is modular, and we recommend only importing the specific
module that you need.

**Before: 1st gen**

```javascript
const functions = require("firebase-functions/v1");
```

**After: 2nd gen**

```javascript
// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
```

> [!NOTE]
> **Note:** Remember, it is not possible to mix imports within a function. Features that are supported only by 2nd gen will not work with a v1 import, and the other way around.

## Update trigger definitions

Since the 2nd gen SDK favors modular imports, update trigger definitions to
reflect the changed imports from the previous step.

The arguments passed to callbacks for some triggers have changed. In this
example, note that the arguments to the `onDocumentCreated` callback have been
consolidated into a single `event` object. Additionally, some triggers have
convenient new configuration features, like the `onRequest` trigger's `cors`
option.

**Before: 1st gen**

```javascript
const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  // ...
});

exports.uppercase = functions.firestore
  .document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });
```

**After: 2nd gen**

```javascript
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

exports.date = onRequest({cors: true}, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});
```

## Minimize rewrite efforts with JavaScript destructuring

If your functions have complex bodies that rely heavily on 1st gen context or
provider-specific parameters (like `message` or `snapshot`), you can use the 1st
gen compatibility helpers built into the 2nd gen SDK.

The 2nd gen SDK automatically patches the event object with getters that match
1st gen signatures. This lets you use JavaScript destructuring to extract
these properties directly in the handler signature, minimizing the need to
rewrite your function logic.

### Provider mapping reference

|---|---|---|
| **Provider** | **1st gen Arguments** | **2nd gen Patched Event Destructuring** |
| Pub/Sub | `(message, context)` | `({ message, context }) => { ... }` |
| Cloud Firestore | `(snapshot, context)` | `({ snapshot, context }) => { ... }` |
| Cloud Storage | `(object, context)` | `({ object, context }) => { ... }` |
| Realtime Database | `(snapshot, context)` | `({ snapshot, context }) => { ... }` |
| Remote Config | `(version, context)` | `({ version, context }) => { ... }` |
| Cloud Scheduler | `(context)` | `({ context }) => { ... }` |
| Task Queue | `(data, context)` | `({ data, context }) => { ... }` |

**Before (1st gen):**

```javascript
export const myPubSubV1 = functions.pubsub.topic("my-topic").onPublish((message, context) => {
  const data = message.json;
  const eventId = context.eventId;
  // ... rest of the logic
});
```

**New Alternative (2nd gen with Destructuring):**

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

export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
  // No need to change the function body!
  const data = message.json;      // Uses v1 Message wrapper
  const eventId = context.eventId; // Uses v1 EventContext map
  // ... rest of the logic
});
```

## Use parameterized configuration

2nd gen functions drop support for `functions.config` in favor of a more secure
interface for [defining configuration parameters declaratively](https://firebase.google.com/docs/functions/config-env.md.txt#params)
inside your codebase.
With the new `params` module, the CLI blocks deployment unless all parameters
have a valid value, ensuring that a function isn't deployed with missing
configuration.

**Before: 1st gen**

```javascript
const functions = require("firebase-functions/v1");

exports.getQuote = functions.https.onRequest(async (req, res) => {
  const quote = await fetchMotivationalQuote(functions.config().apiKey);
  // ...
});
```

**After: 2nd gen**

```javascript
const {onRequest} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");

// Define the secret parameter
const apiKey = defineSecret("API_KEY");

exports.getQuote = onRequest(
  // make the secret available to this function
  { secrets: [apiKey] },
  async (req, res) => {
    // retrieve the value of the secret
    const quote = await fetchMotivationalQuote(apiKey.value());
    // ...
  }
);
```

If you have existing environment configuration with `functions.config`, migrate
this configuration as part of your upgrade to 2nd gen.

The `functions.config` API is deprecated will be decommissioned in March 2027.
**After that date, deployments with `functions.config` will fail.**

To prevent deployment failures, migrate your configuration to
Cloud Secret Manager using the Firebase CLI. This is strongly recommended as
the most efficient and secure way to migrate your configuration.

1. **Export configuration with the Firebase CLI**

   Use the `config export` command to export your existing environment config to a
   new secret in Cloud Secret Manager:

   ````bash
   $ firebase functions:config:export
   i  This command retrieves your Runtime Config values (accessed via functions.config())
      and exports them as a Secret Manager secret.

   i  Fetching your existing functions.config() from your project...  ✔
      Fetched your existing functions.config().

   i  Configuration to be exported:
   ⚠  This may contain sensitive data. Do not share this output.

   {
      ...
   }

   ✔ What would you like to name the new secret for your configuration? RUNTIME_CONFIG

   ✔  Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```
   ````
2. **Update function code to bind secrets**

   To use configuration stored in the new secret in Cloud Secret Manager, use the
   `defineJsonSecret` API in your function source. Also, make sure that secrets are
   bound to all functions that need them.

   **Before**

   ```javascript
   const functions = require("firebase-functions/v1");

   exports.myFunction = functions.https.onRequest((req, res) => {
     const apiKey = functions.config().someapi.key;
     // ...
   });
   ```

   **After**

   ```javascript
   const { onRequest } = require("firebase-functions/v2/https");
   const { defineJsonSecret } = require("firebase-functions/params");

   const config = defineJsonSecret("RUNTIME_CONFIG");

   exports.myFunction = onRequest(
     // Bind secret to your function
     { secrets: [config] },
     (req, res) => {
       // Access secret values via .value()
       const apiKey = config.value().someapi.key;
       // ...
   });
   ```
3. **Deploy Functions**

   Deploy your updated functions to apply the changes and bind the secret
   permissions.

   ```bash
   firebase deploy --only functions:<your-function-name>
   ```

## Set runtime options

Configuration of [runtime options](https://firebase.google.com/docs/functions/manage-functions.md.txt#set-runtime-options)
has changed between 1st and 2nd gen. 2nd gen also adds a new capability to
set options for all functions.

**Before: 1st gen**

```javascript
const functions = require("firebase-functions/v1");

exports.date = functions
  .runWith({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  })
  // locate function closest to users
  .region("asia-northeast1")
  .https.onRequest((req, res) => {
    // ...
  });

exports.uppercase = functions
  // locate function closest to users and database
  .region("asia-northeast1")
  .firestore.document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });
```

**After: 2nd gen**

```javascript
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions/v2");

// locate all functions closest to users
setGlobalOptions({ region: "asia-northeast1" });

exports.date = onRequest({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  }, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});
```

## Update default service account (optional)

While 1st gen functions use the Google App Engine default service account to
authorize access to Firebase APIs, 2nd gen functions use the Compute Engine
default service account. This difference can lead to permissions issues for
functions migrated to 2nd gen in cases where you have granted special
permissions to the 1st gen service account. If you haven't changed any service
account permissions, you can skip this step.

The recommended solution is to explicitly assign the existing 1st gen App Engine
default service account to functions that you want to migrate to 2nd gen,
overriding the 2nd gen default. You can do this by making sure each migrated
function sets the correct value for `serviceAccountEmail`:

```javascript
const {onRequest} = require("firebase-functions/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions");

// Use the App Engine default service account for all functions
setGlobalOptions({serviceAccountEmail: '<my-project-number>@<wbr>appspot.gserviceaccount.com'});

// Now I use the App Engine default service account.
exports.date = onRequest({cors: true}, (req, res) => {
  // ...
});

// I do too!
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  // ...
});
```

Alternatively, you could make sure to modify the service account details to
match all the necessary permissions on both the App Engine default service
account (for 1st Gen) and the Compute Engine default service account (for 2nd
Gen).

## Use concurrency

A significant advantage of 2nd gen functions is the ability of a single function
instance to serve more than one request at once. This can dramatically reduce
the number of cold starts experienced by end users. By default, concurrency is
set at 80, but you can set it to any value from 1 to 1000:

```javascript
const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});
```

Tuning concurrency can improve performance and reduce cost of functions.
Learn more about concurrency in [Allow concurrent requests](https://firebase.google.com/docs/functions/manage-functions.md.txt#allow_concurrent_requests).

### Audit global variable usage

1st gen functions written without concurrency in mind might use global variables
that are set and read on each request. When concurrency is enabled and a single
instance starts handling multiple requests at once, this may introduce bugs in
your function as concurrent requests start setting and reading global variables
simultaneously.

While upgrading, you can set your function's CPU to `gcf_gen1` and set
`concurrency` to 1 to restore 1st gen behavior:

```javascript
const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // TEMPORARY FIX: remove concurrency
    cpu: "gcf_gen1",
    concurrency: 1
  },
  (req, res) => {
    // ...
});
```

However, this is not recommended as a long-term fix, because it forfeits the
performance advantages of 2nd gen functions. Instead, audit usage of global
variables in your functions, and remove these temporary settings when you're
ready.

## Migrate traffic to the new 2nd gen functions

Just as when [changing a function's region or trigger type](https://firebase.google.com/docs/functions/manage-functions.md.txt#modify),
you'll need to give the 2nd gen function a new name and slowly migrate
traffic to it.

It is not possible to upgrade a function from 1st to 2nd gen with the same name
and run `firebase deploy`. Doing so will result in the error:

    Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.

The migration strategy depends on the type of trigger your function uses.

### Migrate Callable, Task Queue, and HTTP triggers

These triggers are direct invocations. Because the 2nd gen function will have a
new name (and a new URL for HTTP triggers), you can migrate traffic by updating
the clients.

1. Rename the function in your code (for example, rename `myCallable` to `myCallableV2`).
2. Deploy the function. Both the 1st gen and 2nd gen functions are now running.
3. Update your client code or caller to point to the new 2nd gen function's name or URL.
4. Once all traffic has shifted to the new function, delete the 1st gen function using the Firebase CLI's `firebase functions:delete` command.

### Migrate background triggers

Background triggers (such as Pub/Sub, Cloud Firestore, and
Cloud Storage triggers)
respond to events in your project. To avoid missing any
events during the transition, you must temporarily run both the 1st gen and
2nd gen functions side-by-side.

During the transition period, both functions will trigger on the same event.
This means your business logic will run twice per event. Ensure your function
is [idempotent](https://firebase.google.com/docs/functions/tips.md.txt#write_idempotent_functions)
before proceeding.

1. Add the 2nd gen function alongside the 1st gen function, keeping the existing
   1st gen function in your code, and adding the 2nd gen function
   listening to the same event source.

   > [!TIP]
   > **Tip:** Use a passthrough for verification. To avoid duplicating your business logic in your codebase during the transition, or to verify that the 2nd gen function is correctly receiving events before fully trusting it, make the 2nd gen function a passthrough that calls the 1st gen function using the `run` method.

   ```javascript
   import * as functions from "firebase-functions/v1";
   import { onMessagePublished } from "firebase-functions/v2/pubsub";

   // --- Existing 1st gen function ---
   export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => {
     console.log("V1 handler running for event:", context.eventId);
     // ... existing v1 function logic ...
   });

   // --- New v2 passthrough function ---
   export const myPubSubV2 = onMessagePublished("my-topic", async ({ message, context }) => {
     console.log("v2 handler triggering V1 for event:", context.eventId);
     // Call the v1 function's handler
     await myPubSub.run(message, context);
   });
   ```
2. Run `firebase deploy`. Both functions are now active and listening to the
   same events.

3. Verify the 2nd gen function is receiving traffic. Monitor the logs for both
   functions. Ensure that the 2nd gen function is invoked
   for all events and that calls are succeeding.

4. Once you're confident that the function is performing correctly, move the
   actual
   business logic from the 1st gen function into
   the 2nd gen function's body. If you used the passthrough method, remove the
   call to `myPubSub.run()`.

   ```javascript
   import * as functions from "firebase-functions/v1";
   import { onMessagePublished } from "firebase-functions/v2/pubsub";

   // --- Existing v1 function (to be removed next) ---
   export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => {
     console.log("v1 handler running for event:", context.eventId);
     // ... existing v1 function logic ...
   });

   // --- New v2 function with full logic ---
   export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
     console.log("v2 handler running for event:", context.eventId);
     // ... existing v1 function logic WAS MOVED HERE ...
   });
   ```

   Deploy this change.
5. Remove the 1st gen function definition from your code and redeploy. The CLI
   will
   prompt you to delete the 1st gen function from Google Cloud.