<br />

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:** Cloud Functions for Firebase (2nd gen) also provides Python support. You can [get started](https://firebase.google.com/docs/functions/get-started) with Python using our basic tutorial's snippets and instructions.

The examples in this page 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 file. This
allows for easy migration piece by piece, as you're ready. We recommend
migrating one function at a time, performing testing and verification before
proceeding.

## Verify Firebase CLI and `firebase-function`s 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**  

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

**After: 2nd gen**  

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

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

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

    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) => {
      /* ... */
    });

## 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?gen=2nd#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.

### Migrate to the `params` subpackage

If you have been using environment configuration with `functions.config`, you
can migrate your existing configuration by refactoring it as [parameterized
configuration](https://firebase.google.com/docs/functions/config-env#params). For example:

**Before: 1st gen**  

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

    exports.date = functions.https.onRequest((req, res) => {
      const date = new Date();
      const formattedDate =
    date.toLocaleDateString(functions.config().dateformat);

      // ...
    });

**After: 2nd gen**  

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

    const dateFormat = defineString("DATE_FORMAT");

    exports.date = onRequest((req, res) => {
      const date = new Date();
      const formattedDate = date.toLocaleDateString(dateFormat.value());

      // ...
    });

### Migrating Nested Configuration

If your `functions.config()` usage involved nested objects, the
`defineJsonSecret` parameter type offers a straightforward migration path. You
can store the entire JSON structure from `functions.config()` directly in a
single secret.

For example, if you had:

**Before: 1st gen**  

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

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

You can migrate by storing the entire `someapi` object as a JSON string in a
secret named `SOMEAPI_CONFIG` and use `defineJsonSecret`:

**After: 2nd gen**  

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

    const someApiConfig = defineJsonSecret("SOMEAPI_CONFIG");

    exports.myFunction = onRequest(<mark>{ secrets: [someApiConfig] }</mark>, (req, res) => {
      const apiKey = someApiConfig.value().key;
      const webhookSecret = someApiConfig.value().webhookSecret;
      // ...
    });

Note that, unlike `functions.config()`, any secret defined with `defineSecret`
or `defineJsonSecret` must be explicitly bound to the function using the `{
secrets: [...] }` option to be accessible at runtime.

This preserves the configuration structure and minimizes code changes. You can
use the Firebase CLI to help export your existing `functions.config()` JSON and
set it as the value for the new secret. See [Managing
secrets](https://firebase.google.com/docs/functions/config-env?gen=2nd#managing_secrets) for instructions
on setting secret values, including how to set JSON secrets from a file or
stdin.

### Set parameter values

The first time you deploy, the Firebase CLI prompts for all values of
parameters, and save the values in a dotenv file. To export your
`functions.config` values, run `firebase functions:config:export`.

For additional safety, you can also specify parameter
[types](https://firebase.google.com/docs/functions/config-env?gen=2nd#parameter_types) and [validation
rules](https://firebase.google.com/docs/functions/config-env?gen=2nd#configure_behavior).

### Special case: API Keys

The `params` module integrates with Cloud Secret Manager, which provides
fine-grained access control to sensitive values like API keys. See [secret
parameters](https://firebase.google.com/docs/functions/config-env?gen=2nd#secret-parameters) and
[Structured JSON Secrets](https://firebase.google.com/docs/functions/config-env?gen=2nd#json-secrets) for
more information.

**Before: 1st gen**  

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

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

**After: 2nd gen**  

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

## Set runtime options

Configuration of [runtime options](https://firebase.google.com/docs/functions/manage-functions?gen=2nd#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**  

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

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

    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:  

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

    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, as 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?gen=2nd#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.

Before you follow these steps, first ensure that your function is
[idempotent](https://firebase.google.com/docs/functions/tips#write_idempotent_functions), since both the new
version and the old version of your function will be running at the same time
during the change. For example, if you have a 1st gen function that responds to
write events in Firestore, ensure that responding to a write twice, once by the
1st gen function and once by the 2nd gen function, in response to those events
leaves your app in a consistent state.

1. Rename the function in your functions code. For example, rename `resizeImage` to `resizeImageSecondGen`.
2. Deploy the function, so that both the original 1st gen function and 2nd gen function are running.
   1. In the case of callable, Task Queue, and HTTP triggers, begin pointing all clients to the 2nd gen function by updating client code with the 2nd gen function's name or URL.
   2. With background triggers, both the 1st gen and 2nd gen functions will respond to every event immediately upon deploy.
3. When all traffic is migrated off, delete the 1st gen function using the firebase CLI's `firebase functions:delete` command.
   1. Optionally, rename the 2nd gen function to match the name of the 1st gen function.