Invoke Genkit flows from your App

Cloud Functions for Firebase has an onCallGenkit method that lets you create a callable function with a Genkit action (a Flow). These functions can be called with genkit/beta/client or the Cloud Functions client SDKs, which automatically add auth information.

Before you begin

  • You should be familiar with Genkit's concept of flows, and how to write them. The instructions on this page assume that you already have defined some flows that you want to deploy.
  • It's helpful, but not required, if you've used Cloud Functions for Firebase before.

Set up a Firebase project

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

  2. Upgrade the project to the Blaze plan, which is required for Cloud Functions production deployment.

  3. Install the Firebase CLI.

  4. Log in with the Firebase CLI:

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

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  6. Initialize a Firebase project in the directory:

    cd $PROJECT_ROOT
    firebase init functions

The rest of this page assumes that you've chosen to write your functions in JavaScript.

Wrap the flow in onCallGenkit

After you've set up a Firebase project with Cloud Functions, you can copy or write flow definitions in the project's functions directory. Here is an example flow to demonstrate this:

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

const jokeTeller = ai.defineFlow({
  name: "jokeTeller",
  inputSchema: z.string().nullable(),
  outputSchema: z.string(),
  streamSchema: z.string(),
}, async (jokeType = "knock-knock", {sendChunk}) => {
  const prompt = `Tell me a ${jokeType} joke.`;

  // Call the `generateStream()` method to
  // receive the `stream` async iterable.
  const {stream, response: aiResponse} = ai.generateStream(prompt);

  // Send new words of the generative AI response
  // to the client as they are generated.
  for await (const chunk of stream) {
    sendChunk(chunk.text);
  }

  // Return the full generative AI response
  // to clients that may not support streaming.
  return (await aiResponse).text;
},
);

To deploy a flow like this one, wrap it with onCallGenkit, available in firebase-functions/https. This helper method has all the features of callable functions, and it automatically supports both streaming and JSON responses.

const {onCallGenkit} = require("firebase-functions/v2/https");
exports.tellJoke = onCallGenkit({
  // Bind the Gemini API key secret parameter to the function.
  secrets: [apiKey],
},
// Pass in the genkit flow.
jokeTeller,
);

Make API credentials available to deployed flows

Once deployed, your flows need a way to authenticate with any remote services they rely on. At a minimum, most flows need credentials for accessing the model API service they use.

For this example, 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.js and add the following after the existing imports:

    const {defineSecret} = require("firebase-functions/params");
    // Store the Gemini API key in Cloud Secret Manager.
    const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");
    

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

    // Bind the Gemini API key secret parameter to the function.
    secrets: [apiKey],
    

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.

(Optional) Add App Check enforcement

Firebase App Check uses native attestation to verify that your API is only being called by your application. onCallGenkit supports App Check enforcement declaratively.

export const generatePoem = onCallGenkit({
  enforceAppCheck: true,
  // Optional. Makes App Check tokens only usable once. This adds extra security
  // at the expense of slowing down your app to generate a token for every API
  // call
  consumeAppCheckToken: true,
}, generatePoemFlow);

Configure CORS (Cross-Origin Resource Sharing)

Use the cors option to control which origins can access your function.

By default, callable functions have CORS configured to allow requests from all origins. To allow some cross-origin requests, but not all, pass a list of specific domains or regular expressions that should be allowed. For example:

export const tellJoke = onCallGenkit({
  cors: 'mydomain.com',
}, jokeTeller);

Complete example

After you've made all of the changes described above, your deployable flow will look something like the following example:

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

// Dependencies for Genkit.
const {gemini15Flash, googleAI} = require("@genkit-ai/googleai");
const {genkit, z} = require("genkit");

// Store the Gemini API key in Cloud Secret Manager.
const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

const jokeTeller = ai.defineFlow({
  name: "jokeTeller",
  inputSchema: z.string().nullable(),
  outputSchema: z.string(),
  streamSchema: z.string(),
}, async (jokeType = "knock-knock", {sendChunk}) => {
  const prompt = `Tell me a ${jokeType} joke.`;

  // Call the `generateStream()` method to
  // receive the `stream` async iterable.
  const {stream, response: aiResponse} = ai.generateStream(prompt);

  // Send new words of the generative AI response
  // to the client as they are generated.
  for await (const chunk of stream) {
    sendChunk(chunk.text);
  }

  // Return the full generative AI response
  // to clients that may not support streaming.
  return (await aiResponse).text;
},
);

exports.tellJoke = onCallGenkit({
  // Bind the Gemini API key secret parameter to the function.
  secrets: [apiKey],
},
// Pass in the genkit flow.
jokeTeller,
);

Deploy flows to Firebase

After you've defined flows using onCallGenkit, you can deploy them as you would deploy other functions:

cd $PROJECT_ROOT
firebase deploy --only functions