Genkit with Cloud Functions for Firebase

Firebase Genkit includes a plugin that helps you deploy your flows to Firebase Cloud Functions. This page, as an example, walks you through the process of deploying the default sample flow to Firebase.

Deploy a flow as a Cloud Function

  1. Install the required tools:

    1. Make sure you are using Node.js version 20 or higher (run node --version to check).

    2. Install the Firebase CLI.

  2. Create a new Firebase project using the Firebase console or choose an existing one.

    Upgrade the project to the Blaze plan, which is required to deploy Cloud Functions.

  3. Log in with the Firebase CLI:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  4. Create a new project directory:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  5. Initialize a Firebase project with Genkit in the folder:

    cd $PROJECT_ROOT
    firebase init genkit
    • Select the project you created earlier.
    • Select the model provider you want to use.

    Accept the defaults for the remaining prompts. The genkit tool will create some sample source files to get you started developing your own AI flows. For the rest of this tutorial, however, you'll just deploy the sample flow.

  6. Make API credentials available to your Cloud Function. Do one of the following, depending on the model provider you chose:

    Gemini (Google AI)

    1. Make sure Google AI is available in your region.

    2. Generate an API key for the Gemini API using Google AI Studio.

    3. Store your API key in Cloud Secret Manager:

      firebase functions:secrets:set GOOGLE_GENAI_API_KEY

      This step is important to prevent accidentally leaking your API key, which grants access to a potentially metered service.

      See Store and access sensitive configuration information for more information on managing secrets.

    4. Edit src/index.ts and add the following after the existing imports:

      import {defineSecret} from "firebase-functions/params";
      const googleAIapiKey = defineSecret("GOOGLE_GENAI_API_KEY");
      

      Then, in the flow definition, declare that the cloud function needs access to this secret value:

      export const menuSuggestionFlow = onFlow(
        {
          name: "menuSuggestionFlow",
          // ...
          httpsOptions: {
            secrets: [googleAIapiKey],  // Add this line.
          },
        },
        async (subject) => {
          // ...
        }
      );
      

    Now, when you deploy this function, your API key will be stored in Cloud Secret Manager, and available from the Cloud Functions environment.

    Gemini (Vertex AI)

    1. In the Cloud console, Enable the Vertex AI API for your Firebase project.

    2. On the IAM page, ensure that the Default compute service account is granted the Vertex AI User role.

    The only secret you need to set up for this tutorial is for the model provider, but in general, you must do something similar for each service your flow uses.

  7. If you'll access your flow from a web app (which you will be doing in the next section), in the httpsOptions parameter, set a CORS policy:

    export const menuSuggestionFlow = onFlow(
      {
        name: "menuSuggestionFlow",
        // ...
        httpsOptions: {
          cors: true,  // Add this line.
        },
      },
      async (subject) => {
        // ...
      }
    );
    

    You will likely want a more restrictive policy for production apps, but this will do for this tutorial.

  8. Optional: Try your flow in the developer UI:

    1. Make API credentials available locally. Do one of the following, depending on the model provider you chose:

      Gemini (Google AI)

      Set the GOOGLE_GENAI_API_KEY environment variable to your key:

      export GOOGLE_GENAI_API_KEY=<your API key>

      Gemini (Vertex AI)

      Set some additional environment variables and use the gcloud tool to set up application default credentials locally:

      export GCLOUD_PROJECT=<your project ID>
      export GCLOUD_LOCATION=us-central1
      gcloud auth application-default login
    2. Start the UI:

      cd $PROJECT_ROOT/functions
      genkit start
    3. In the developer UI (http://localhost:4000/), run the flow:

      1. Click menuSuggestionFlow.

      2. On the Input JSON tab, provide a subject for the model:

        "AI app developers"
        
      3. On the Auth JSON tab, provide a simulated auth object:

        {
          "uid": 0,
          "email_verified": true
        }
        
      4. Click Run.

  9. If everything's working as expected so far, you can deploy the flow:

    cd $PROJECT_ROOT
    firebase deploy --only functions

You've now deployed the flow as a Cloud Function! But, you won't be able to access your deployed endpoint with curl or similar, because of the flow's authorization policy. Continue to the next section to learn how to securely access the flow.

Try the deployed flow

It is critical that every flow you deploy sets an authorization policy. Without one, your potentially-expensive generative AI flows would be invocable by anyone.

The default sample flow has an authorization policy like the following:

firebaseAuth((user) => {
  if (!user.email_verified) {
    throw new Error('Verified email required to run flow');
  }
});

This policy uses the firebaseAuth() helper to allow access only to registered users of your app with verfied email addresses. On the client side, you need to set the Authorization: Bearer header to a Firebase ID token that satisfies your policy. The Cloud Functions client SDKs provide callable function methods that automate this.

To try out your flow endpoint, you can deploy the following minimal example web app:

  1. In the Project settings section of the Firebase console, add a new web app, selecting the option to also set up Hosting.

  2. In the Authentication section of the Firebase console, enable the Google provider, which you will use in this example.

  3. In your project directory, set up Firebase Hosting, where you will deploy the sample app:

    cd $PROJECT_ROOT
    firebase init hosting

    Accept the defaults for all of the prompts.

  4. Replace public/index.html with the following:

    <!doctype html>
    <html>
      <head>
        <title>Genkit demo</title>
      </head>
      <body>
        <div id="signin" hidden>
          <button id="signinBtn">Sign in with Google</button>
        </div>
        <div id="callGenkit" hidden>
          Subject: <input type="text" id="subject" />
          <button id="suggestMenuItem">Suggest a menu theme</button>
          <p id="menuItem"></p>
        </div>
        <script type="module">
          import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.10.0/firebase-app.js';
          import {
            getAuth,
            onAuthStateChanged,
            GoogleAuthProvider,
            signInWithPopup,
          } from 'https://www.gstatic.com/firebasejs/10.10.0/firebase-auth.js';
          import {
            getFunctions,
            httpsCallable,
          } from 'https://www.gstatic.com/firebasejs/10.10.0/firebase-functions.js';
    
          const firebaseConfig = await fetch('/__/firebase/init.json');
          initializeApp(await firebaseConfig.json());
    
          async function generateMenuItem() {
            const menuSuggestionFlow = httpsCallable(
              getFunctions(),
              'menuSuggestionFlow'
            );
            const subject = document.querySelector('#subject').value;
            const response = await menuSuggestionFlow(subject);
            document.querySelector('#menuItem').innerText = response.data;
          }
    
          function signIn() {
            signInWithPopup(getAuth(), new GoogleAuthProvider());
          }
    
          document
            .querySelector('#signinBtn')
            .addEventListener('click', signIn);
          document
            .querySelector('#suggestMenuItem')
            .addEventListener('click', generateMenuItem);
    
          const signinEl = document.querySelector('#signin');
          const genkitEl = document.querySelector('#callGenkit');
    
          onAuthStateChanged(getAuth(), (user) => {
            if (!user) {
              signinEl.hidden = false;
              genkitEl.hidden = true;
            } else {
              signinEl.hidden = true;
              genkitEl.hidden = false;
            }
          });
        </script>
      </body>
    </html>
    
  5. Deploy the web app and Cloud Function:

    cd $PROJECT_ROOT
    firebase deploy

Open the web app by visiting the URL printed by the deploy command. The app requires you to sign in with a Google account, after which you can initiate endpoint requests.

Developing using Firebase Local Emulator Suite

Firebase offers a suite of emulators for local development, which you can use with Genkit.

To use Genkit with the Firebase Emulator Suite, start the the Firebase emulators like this:

GENKIT_ENV=dev firebase emulators:start --inspect-functions

This will run your code in the emulator and run the Genkit framework in development mode, which launches and exposes the Genkit reflection API (but not the Dev UI).

Then, launch the Genkit Dev UI with the --attach option to connect it to your code running inside the Firebase Emulator:

genkit start --attach http://localhost:3100 --port 4001

To see traces from Firestore in the Dev UI you can navigate to the Inspect tab and toggle the "Dev/Prod" switch. When toggled to "prod" it will be loading traces from firestore.