Deploying AI Workflows: Guidance on how to deploy Genkit code to various environments including Firebase and Cloud Run or use within a Next.js app. # Authorization and integrity > This document explains how to manage authorization and integrity in Genkit applications, covering Firebase and non-Firebase HTTP authorization. When building any public-facing application, it’s extremely important to protect the data stored in your system. When it comes to LLMs, extra diligence is necessary to ensure that the model is only accessing data it should, tool calls are properly scoped to the user invoking the LLM, and the flow is being invoked only by verified client applications. Genkit provides mechanisms for managing authorization policies and contexts. Flows running on Firebase can use an auth policy callback (or helper). Alternatively, Firebase also provides auth context into the flow where it can do its own checks. For non-Functions flows, auth can be managed and set through middleware. ## Authorize within a Flow [Section titled “Authorize within a Flow”](#authorize-within-a-flow) Flows can check authorization in two ways: either the request binding (e.g. `onCallGenkit` for Cloud Functions for Firebase or `express`) can enforce authorization, or those frameworks can pass auth policies to the flow itself, where the flow has access to the information for auth managed within the flow. ```ts import { genkit, z, UserFacingError } from 'genkit'; const ai = genkit({ ... }); export const selfSummaryFlow = ai.defineFlow( { name: 'selfSummaryFlow', inputSchema: z.object({ uid: z.string() }), outputSchema: z.object({ profileSummary: z.string() }), }, async (input, { context }) => { if (!context.auth) { throw new UserFacingErrorError('UNAUTHENTICATED', 'Unauthenticated'); } if (input.uid !== context.auth.uid) { throw new UserFacingError('PERMISSION_DENIED', 'You may only summarize your own profile data.'); } // Flow logic here... return { profileSummary: "User profile summary would go here" }; }); ``` It is up to the request binding to populate `context.auth` in this case. For example, `onCallGenkit` automatically populates `context.auth` (Firebase Authentication), `context.app` (Firebase App Check), and `context.instanceIdToken` (Firebase Cloud Messaging). When calling a flow manually, you can add your own auth context manually. ```ts // Error: Authorization required. await selfSummaryFlow({ uid: 'abc-def' }); // Error: You may only summarize your own profile data. await selfSummaryFlow.run( { uid: 'abc-def' }, { context: { auth: { uid: 'hij-klm' } }, }, ); // Success await selfSummaryFlow( { uid: 'abc-def' }, { context: { auth: { uid: 'abc-def' } }, }, ); ``` When running with the Genkit Development UI, you can pass the Auth object by entering JSON in the “Auth JSON” tab: `{"uid": "abc-def"}`. You can also retrieve the auth context for the flow at any time within the flow by calling `ai.currentContext()`, including in functions invoked by the flow: ```ts import { genkit, z } from 'genkit'; const ai = genkit({ ... });; async function readDatabase(uid: string) { const auth = ai.currentContext()?.auth; // Note: the shape of context.auth depends on the provider. onCallGenkit puts // claims information in auth.token if (auth?.token?.admin) { // Do something special if the user is an admin } else { // Otherwise, use the `uid` variable to retrieve the relevant document } } export const selfSummaryFlow = ai.defineFlow( { name: 'selfSummaryFlow', inputSchema: z.object({ uid: z.string() }), outputSchema: z.object({ profileSummary: z.string() }), authPolicy: ... }, async (input) => { await readDatabase(input.uid); return { profileSummary: "User profile summary would go here" }; } ); ``` When testing flows with Genkit dev tools, you are able to specify this auth object in the UI, or on the command line with the `--context` flag: ```bash genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}' ``` ## Authorize using Cloud Functions for Firebase [Section titled “Authorize using Cloud Functions for Firebase”](#authorize-using-cloud-functions-for-firebase) The Cloud Functions for Firebase SDKs support Genkit including integration with Firebase Auth / Google Cloud Identity Platform, as well as built-in Firebase App Check support. ### User authentication [Section titled “User authentication”](#user-authentication) The `onCallGenkit()` wrapper provided by the Firebase Functions library has built-in support for the Cloud Functions for Firebase [client SDKs](https://firebase.google.com/docs/functions/callable?gen=2nd#call_the_function). When you use these SDKs, the Firebase Auth header is automatically included as long as your app client is also using the [Firebase Auth SDK](https://firebase.google.com/docs/auth). You can use Firebase Auth to protect your flows defined with `onCallGenkit()`: ```ts import { genkit } from 'genkit'; import { onCallGenkit } from 'firebase-functions/https'; const ai = genkit({ ... });; const selfSummaryFlow = ai.defineFlow({ name: 'selfSummaryFlow', inputSchema: z.object({ userQuery: z.string() }), outputSchema: z.object({ profileSummary: z.string() }), }, async ({ userQuery }) => { // Flow logic here... return { profileSummary: "User profile summary based on query would go here" }; }); export const selfSummary = onCallGenkit({ authPolicy: (auth) => auth?.token?.['email_verified'] && auth?.token?.['admin'], }, selfSummaryFlow); ``` When you use `onCallGenkit`, `context.auth` is returned as an object with a `uid` for the user ID, and a `token` that is a [DecodedIdToken](https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth.decodedidtoken). You can always retrieve this object at any time using `ai.currentContext()` as noted earlier. When running this flow during development, you would pass the user object in the same way: ```bash genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}' ``` Whenever you expose a Cloud Function to the wider internet, it is vitally important that you use some sort of authorization mechanism to protect your data and the data of your customers. With that said, there are times when you need to deploy a Cloud Function with no code-based authorization checks (for example, your Function is not world-callable but instead is protected by [Cloud IAM](https://cloud.google.com/functions/docs/concepts/iam)). Cloud Functions for Firebase lets you to do this using the `invoker` property, which controls IAM access. The special value `'private'` leaves the function as the default IAM setting, which means that only callers with the [Cloud Run Invoker role](https://cloud.google.com/run/docs/reference/iam/roles) can execute the function. You can instead provide the email address of a user or service account that should be granted permission to call this exact function. ```ts import { onCallGenkit } from 'firebase-functions/https'; const selfSummaryFlow = ai.defineFlow( { name: 'selfSummaryFlow', inputSchema: z.object({ userQuery: z.string() }), outputSchema: z.object({ profileSummary: z.string() }), }, async ({ userQuery }) => { // Flow logic here... return { profileSummary: "User profile summary based on query would go here" }; }, ); export const selfSummary = onCallGenkit( { invoker: 'private', }, selfSummaryFlow, ); ``` #### Client integrity [Section titled “Client integrity”](#client-integrity) Authentication on its own goes a long way to protect your app. But it’s also important to ensure that only your client apps are calling your functions. The Firebase plugin for genkit includes first-class support for [Firebase App Check](https://firebase.google.com/docs/app-check). Do this by adding the following configuration options to your `onCallGenkit()`: ```ts import { onCallGenkit } from 'firebase-functions/https'; const selfSummaryFlow = ai.defineFlow({ name: 'selfSummaryFlow', inputSchema: z.object({ userQuery: z.string() }), outputSchema: z.object({ profileSummary: z.string() }), }, async ({ userQuery }) => { // Flow logic here... return { profileSummary: "User profile summary based on query would go here" }; }); export const selfSummary = onCallGenkit({ // These two fields for app check. The consumeAppCheckToken option is for // replay protection, and requires additional client configuration. See the // App Check docs. enforceAppCheck: true, consumeAppCheckToken: true, authPolicy: ..., }, selfSummaryFlow); ``` ## Non-Firebase HTTP authorization [Section titled “Non-Firebase HTTP authorization”](#non-firebase-http-authorization) When deploying flows to a server context outside of Cloud Functions for Firebase, you’ll want to have a way to set up your own authorization checks alongside the built-in flows. Use a `ContextProvider` to populate context values such as `auth`, and to provide a declarative policy or a policy callback. The Genkit SDK provides `ContextProvider`s such as `apiKey`, and plugins may expose them as well. For example, the `@genkit-ai/firebase/context` plugin exposes a context provider for verifying Firebase Auth credentials and populating them into context. With code like the following, which might appear in a variety of applications: ```ts // Express app with a simple API key import { genkit, z } from 'genkit'; const ai = genkit({ ... });; export const selfSummaryFlow = ai.defineFlow( { name: 'selfSummaryFlow', inputSchema: z.object({ uid: z.string() }), outputSchema: z.object({ profileSummary: z.string() }), }, async (input) => { // Flow logic here... return { profileSummary: "User profile summary would go here" }; } ); ``` You could secure a simple “flow server” express app by writing: ```ts import { apiKey } from 'genkit/context'; import { startFlowServer, withContextProvider } from '@genkit-ai/express'; startFlowServer({ flows: [withContextProvider(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))], }); ``` Or you could build a custom express application using the same tools: ```ts import { apiKey } from "genkit/context"; import * as express from "express"; import { expressHandler } from "@genkit-ai/express; const app = express(); // Capture but don't validate the API key (or its absence) app.post('/summary', expressHandler(selfSummaryFlow, { contextProvider: apiKey()})) app.listen(process.env.PORT, () => { console.log(`Listening on port ${process.env.PORT}`); }) ``` `ContextProvider`s abstract out the web framework, so these tools work in other frameworks like Next.js as well. Here is an example of a Firebase app built on Next.js. ```ts import { appRoute } from '@genkit-ai/express'; import { firebaseContext } from '@genkit-ai/firebase'; export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext, }); ``` For more information about using Express, see the [Cloud Run](/docs/cloud-run) instructions. # Deploy flows using Cloud Run > This document explains how to deploy Genkit flows as HTTPS endpoints using Google Cloud Run, covering project setup, deployment preparation, and authorization. You can deploy Genkit flows as HTTPS endpoints using Cloud Run. Cloud Run has several deployment options, including container based deployment; this page explains how to deploy your flows directly from code. ## Before you begin [Section titled “Before you begin”](#before-you-begin) * Install the [Google Cloud CLI](https://cloud.google.com/sdk/docs/install). * You should be familiar with Genkit’s concept of [flows](/docs/flows), and how to write them. This page assumes that you already have flows that you want to deploy. * It would be helpful, but not required, if you’ve already used Google Cloud and Cloud Run before. ## 1. Set up a Google Cloud project [Section titled “1. Set up a Google Cloud project”](#1-set-up-a-google-cloud-project) If you don’t already have a Google Cloud project set up, follow these steps: 1. Create a new Google Cloud project using the [Cloud console](https://console.cloud.google.com) or choose an existing one. 2. Link the project to a billing account, which is required for Cloud Run. 3. Configure the Google Cloud CLI to use your project: ```bash gcloud init ``` ## 2. Prepare your Node project for deployment [Section titled “2. Prepare your Node project for deployment”](#2-prepare-your-node-project-for-deployment) For your flows to be deployable, you will need to make some small changes to your project code: ### Add start and build scripts to package.json [Section titled “Add start and build scripts to package.json”](#add-start-and-build-scripts-to-packagejson) When deploying a Node.js project to Cloud Run, the deployment tools expect your project to have a `start` script and, optionally, a `build` script. For a typical TypeScript project, the following scripts are usually adequate: ```json "scripts": { "start": "node lib/index.js", "build": "tsc" }, ``` ### Add code to configure and start the flow server [Section titled “Add code to configure and start the flow server”](#add-code-to-configure-and-start-the-flow-server) In the file that’s run by your `start` script, add a call to `startFlowServer`. This method will start an Express server set up to serve your flows as web endpoints. When you make the call, specify the flows you want to serve: There is also: ```ts import { startFlowServer } from '@genkit-ai/express'; startFlowServer({ flows: [menuSuggestionFlow], }); ``` There are also some optional parameters you can specify: * `port`: the network port to listen on. If unspecified, the server listens on the port defined in the PORT environment variable, and if PORT is not set, defaults to 3400. * `cors`: the flow server’s [CORS policy](https://www.npmjs.com/package/cors#configuration-options). If you will be accessing these endpoints from a web application, you likely need to specify this. * `pathPrefix`: an optional path prefix to add before your flow endpoints. * `jsonParserOptions`: options to pass to Express’s [JSON body parser](https://www.npmjs.com/package/body-parser#bodyparserjsonoptions) ### Optional: Define an authorization policy [Section titled “Optional: Define an authorization policy”](#optional-define-an-authorization-policy) All deployed flows should require some form of authorization; otherwise, your potentially-expensive generative AI flows would be invocable by anyone. When you deploy your flows with Cloud Run, you have two options for authorization: * **Cloud IAM-based authorization**: Use Google Cloud’s native access management facilities to gate access to your endpoints. For information on providing these credentials, see [Authentication](https://cloud.google.com/run/docs/authenticating/overview) in the Cloud Run docs. * **Authorization policy defined in code**: Use the authorization policy feature of the Genkit express plugin to verify authorization info using custom code. This is often, but not necessarily, token-based authorization. If you want to define an authorization policy in code, use the `authPolicy` parameter in the flow definition: ```ts // middleware for handling auth tokens in headers. const authMiddleware = async (req, resp, next) => { // parse auth headers and convert to auth object. (req as RequestWithAuth).auth = { user: await verifyAuthToken(req.header('authorization')), }; next(); }; app.post( '/simpleFlow', authMiddleware, expressHandler(simpleFlow, { authPolicy: ({ auth }) => { if (!auth.user) { throw new Error('not authorized'); } }, }), ); ``` The `auth` parameter of the authorization policy comes from the `auth` property of the request object. You typically set this property using Express middleware. See [Authorization and integrity](/docs/auth#non-firebase-http-authorization). Refer to [express plugin documentation](https://js.api.genkit.dev/modules/_genkit-ai_express.html) for more details. ### Make API credentials available to deployed flows [Section titled “Make API credentials available to deployed flows”](#make-api-credentials-available-to-deployed-flows) Once deployed, your flows need some way to authenticate with any remote services they rely on. Most flows will at a minimum 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. [Generate an API key](https://aistudio.google.com/app/apikey) for the Gemini API using Google AI Studio. 2. Make the API key available in the Cloud Run environment: 1. In the Cloud console, enable the [Secret Manager API](https://console.cloud.google.com/apis/library/secretmanager.googleapis.com?project=_). 2. On the [Secret Manager](https://console.cloud.google.com/security/secret-manager?project=_) page, create a new secret containing your API key. 3. After you create the secret, on the same page, grant your default compute service account access to the secret with the **Secret Manager Secret Accessor** role. (You can look up the name of the default compute service account on the IAM page.) In a later step, when you deploy your service, you will need to reference the name of this secret. * Gemini (Vertex AI) 1. In the Cloud console, [Enable the Vertex AI API](https://console.cloud.google.com/apis/library/aiplatform.googleapis.com?project=_) for your project. 2. On the [IAM](https://console.cloud.google.com/iam-admin/iam?project=_) 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. ## 3. Deploy flows to Cloud Run [Section titled “3. Deploy flows to Cloud Run”](#3-deploy-flows-to-cloud-run) After you’ve prepared your project for deployment, you can deploy it using the `gcloud` tool. * Gemini (Google AI) ```bash gcloud run deploy --update-secrets=GEMINI_API_KEY=:latest ``` * Gemini (Vertex AI) ```bash gcloud run deploy ``` The deployment tool will prompt you for any information it requires. When asked if you want to allow unauthenticated invocations: * Answer `Y` if you’re not using IAM and have instead defined an authorization policy in code. * Answer `N` to configure your service to require IAM credentials. ## Optional: Try the deployed flow [Section titled “Optional: Try the deployed flow”](#optional-try-the-deployed-flow) After deployment finishes, the tool will print the service URL. You can test it with `curl`: ```bash curl -X POST https:///menuSuggestionFlow \ -H "Authorization: Bearer $(gcloud auth print-identity-token)" \ -H "Content-Type: application/json" -d '{"data": "banana"}' ``` # Deploy flows to any Node.js platform > Learn how to deploy Genkit flows to any Node.js platform that can serve an Express.js application, including project setup, configuration, and client-side access. Genkit has built-in integrations that help you deploy your flows to Cloud Functions for Firebase and Google Cloud Run, but you can also deploy your flows to any platform that can serve an Express.js app, whether it’s a cloud service or self-hosted. This page, as an example, walks you through the process of deploying the default sample flow. ## Before you begin [Section titled “Before you begin”](#before-you-begin) * Node.js 20+: Confirm that your environment is using Node.js version 20 or higher (`node --version`). * You should be familiar with Genkit’s concept of [flows](/docs/flows). ## 1. Set up your project [Section titled “1. Set up your project”](#1-set-up-your-project) 1. **Create a directory for the project:** ```bash export GENKIT_PROJECT_HOME=~/tmp/genkit-express-project mkdir -p $GENKIT_PROJECT_HOME cd $GENKIT_PROJECT_HOME mkdir src ``` 2. **Initialize a Node.js project:** ```bash npm init -y ``` 3. **Install Genkit and necessary dependencies:** ```bash npm install --save genkit @genkit-ai/googleai npm install --save-dev typescript tsx npm install -g genkit-cli ``` ## 2. Configure your Genkit app [Section titled “2. Configure your Genkit app”](#2-configure-your-genkit-app) 1. **Set up a sample flow and server:** In `src/index.ts`, define a sample flow and configure the flow server: ```typescript import { genkit, z } from 'genkit'; import { googleAI } from '@genkit-ai/googleai'; import { startFlowServer } from '@genkit-ai/express'; const ai = genkit({ plugins: [googleAI()], model: googleAI.model('gemini-2.5-flash'), }); const helloFlow = ai.defineFlow( { name: 'helloFlow', inputSchema: z.object({ name: z.string() }), outputSchema: z.object({ greeting: z.string() }), }, async (input) => { const { text } = await ai.generate('Say hello to ${input.name}'); return { greeting: text }; }, ); startFlowServer({ flows: [helloFlow], }); ``` There are also some optional parameters for `startFlowServer` you can specify: * `port`: the network port to listen on. If unspecified, the server listens on the port defined in the PORT environment variable, and if PORT is not set, defaults to 3400. * `cors`: the flow server’s [CORS policy](https://www.npmjs.com/package/cors#configuration-options). If you will be accessing these endpoints from a web application, you likely need to specify this. * `pathPrefix`: an optional path prefix to add before your flow endpoints. * `jsonParserOptions`: options to pass to Express’s [JSON body parser](https://www.npmjs.com/package/body-parser#bodyparserjsonoptions) 2. **Set up model provider credentials:** Configure the required environment variables for your model provider. This guide uses the Gemini API from Google AI Studio as an example. [Get an API key from Google AI Studio](https://makersuite.google.com/app/apikey) After you’ve created an API key, set the `GEMINI_API_KEY` environment variable to your key with the following command: ```bash export GEMINI_API_KEY= ``` Different providers for deployment will have different ways of securing your API key in their environment. For security, ensure that your API key is not publicly exposed. ## 3. Prepare your Node.js project for deployment [Section titled “3. Prepare your Node.js project for deployment”](#3-prepare-your-nodejs-project-for-deployment) ### Add start and build scripts to `package.json` [Section titled “Add start and build scripts to package.json”](#add-start-and-build-scripts-to-packagejson) To deploy a Node.js project, define `start` and `build` scripts in `package.json`. For a TypeScript project, these scripts will look like this: ```json "scripts": { "start": "node --watch lib/index.js", "build": "tsc" }, ``` ### Build and test locally [Section titled “Build and test locally”](#build-and-test-locally) Run the build command, then start the server and test it locally to confirm it works as expected. ```bash npm run build npm start ``` In another terminal window, test the endpoint: ```bash curl -X POST "http://127.0.0.1:3400/helloFlow" \ -H "Content-Type: application/json" \ -d '{"data": {"name": "Genkit"}}' ``` ## Optional: Start the Developer UI [Section titled “Optional: Start the Developer UI”](#optional-start-the-developer-ui) You can use the Developer UI to test flows interactively during development: ```bash genkit start -- npm run start ``` Navigate to `http://localhost:4000/flows` to test your flows in the UI. ## 4. Deploy the project [Section titled “4. Deploy the project”](#4-deploy-the-project) Once your project is configured and tested locally, you can deploy to any Node.js-compatible platform. Deployment steps vary by provider, but generally, you configure the following settings: | Setting | Value | | ------------------------- | ---------------------------------------------------------------- | | **Runtime** | Node.js 20 or newer | | **Build command** | `npm run build` | | **Start command** | `npm start` | | **Environment variables** | Set `GEMINI_API_KEY=` and other necessary secrets. | The `start` command (`npm start`) should point to your compiled entry point, typically `lib/index.js`. Be sure to add all necessary environment variables for your deployment platform. After deploying, you can use the provided service URL to invoke your flow as an HTTPS endpoint. ## Call your flows from the client [Section titled “Call your flows from the client”](#call-your-flows-from-the-client) In your client-side code (e.g., a web application, mobile app, or another service), you can call your deployed flows using the Genkit client library. This library provides functions for both non-streaming and streaming flow calls. First, install the Genkit library: ```bash npm install genkit ``` Then, you can use `runFlow` for non-streaming calls and `streamFlow` for streaming calls. ### Non-streaming Flow Calls [Section titled “Non-streaming Flow Calls”](#non-streaming-flow-calls) For a non-streaming response, use the `runFlow` function. This is suitable for flows that return a single, complete output. ```typescript import { runFlow } from 'genkit/beta/client'; async function callHelloFlow() { try { const result = await runFlow({ url: 'http://127.0.0.1:3400/helloFlow', // Replace with your deployed flow's URL input: { name: 'Genkit User' }, }); console.log('Non-streaming result:', result.greeting); } catch (error) { console.error('Error calling helloFlow:', error); } } callHelloFlow(); ``` ### Streaming Flow Calls [Section titled “Streaming Flow Calls”](#streaming-flow-calls) For flows that are designed to stream responses (e.g., for real-time updates or long-running operations), use the `streamFlow` function. ```typescript import { streamFlow } from 'genkit/beta/client'; async function streamHelloFlow() { try { const result = streamFlow({ url: 'http://127.0.0.1:3400/helloFlow', // Replace with your deployed flow's URL input: { name: 'Streaming User' }, }); // Process the stream chunks as they arrive for await (const chunk of result.stream) { console.log('Stream chunk:', chunk); } // Get the final complete response const finalOutput = await result.output; console.log('Final streaming output:', finalOutput.greeting); } catch (error) { console.error('Error streaming helloFlow:', error); } } streamHelloFlow(); ``` ### Authentication (Optional) [Section titled “Authentication (Optional)”](#authentication-optional) If your deployed flow requires authentication, you can pass headers with your requests: ```typescript const result = await runFlow({ url: 'http://127.0.0.1:3400/helloFlow', // Replace with your deployed flow's URL headers: { Authorization: 'Bearer your-token-here', // Replace with your actual token }, input: { name: 'Authenticated User' }, }); ``` # Deploy flows using Cloud Functions for Firebase > Learn how to deploy Genkit flows as callable functions using Cloud Functions for Firebase, including setup, authorization, and client-side access. Cloud Functions for Firebase has an `onCallGenkit` method that lets you quickly create a [callable function](https://firebase.google.com/docs/functions/callable?gen=2nd) with a Genkit action (e.g. a Flow). These functions can be called using `genkit/beta/client`or the [Functions client SDK](https://firebase.google.com/docs/functions/callable?gen=2nd#call_the_function), which automatically adds auth info. ## Before you begin [Section titled “Before you begin”](#before-you-begin) * You should be familiar with Genkit’s concept of [flows](/docs/flows), and how to write them. The instructions on this page assume that you already have some flows defined, which you want to deploy. * It would be helpful, but not required, if you’ve already used Cloud Functions for Firebase before. ## 1. Set up a Firebase project [Section titled “1. Set up a Firebase project”](#1-set-up-a-firebase-project) If you don’t already have a Firebase project with TypeScript Cloud Functions set up, follow these steps: 1. Create a new Firebase project using the [Firebase console](https://console.firebase.google.com/) or choose an existing one. 2. Upgrade the project to the Blaze plan, which is required to deploy Cloud Functions. 3. Install the [Firebase CLI](https://firebase.google.com/docs/cli). 4. Log in with the Firebase CLI: ```bash firebase login firebase login --reauth # alternative, if necessary firebase login --no-localhost # if running in a remote shell ``` 5. Create a new project directory: ```bash export PROJECT_ROOT=~/tmp/genkit-firebase-project1 mkdir -p $PROJECT_ROOT ``` 6. Initialize a Firebase project in the directory: ```bash cd $PROJECT_ROOT firebase init genkit ``` The rest of this page assumes that you’ve decided to write your functions in TypeScript, but you can also deploy your Genkit flows if you’re using JavaScript. ## 2. Wrap the Flow in onCallGenkit [Section titled “2. Wrap the Flow in onCallGenkit”](#2-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/src` directory, and export them in `index.ts`. For your flows to be deployable, you need to wrap them in `onCallGenkit`. This method has all the features of the normal `onCall`. It automatically supports both streaming and JSON responses. Suppose you have the following flow: ```ts const generatePoemFlow = ai.defineFlow( { name: 'generatePoem', inputSchema: z.object({ subject: z.string() }), outputSchema: z.object({ poem: z.string() }), }, async ({ subject }) => { const { text } = await ai.generate(`Compose a poem about ${subject}.`); return { poem: text }; }, ); ``` You can expose this flow as a callable function using `onCallGenkit`: ```ts import { onCallGenkit } from 'firebase-functions/https'; export generatePoem = onCallGenkit(generatePoemFlow); ``` ### Define an authorization policy [Section titled “Define an authorization policy”](#define-an-authorization-policy) All deployed flows, whether deployed to Firebase or not, should have an authorization policy; without one, anyone can invoke your potentially-expensive generative AI flows. To define an authorization policy, use the `authPolicy` parameter of `onCallGenkit`: ```ts export const generatePoem = onCallGenkit( { authPolicy: (auth) => auth?.token?.email_verified, }, generatePoemFlow, ); ``` This sample uses a manual function as its auth policy. In addition, the https library exports the `signedIn()` and `hasClaim()` helpers. Here is the same code using one of those helpers: ```ts import { hasClaim } from 'firebase-functions/https'; export const generatePoem = onCallGenkit( { authPolicy: hasClaim('email_verified'), }, generatePoemFlow, ); ``` ### Make API credentials available to deployed flows [Section titled “Make API credentials available to deployed flows”](#make-api-credentials-available-to-deployed-flows) Once deployed, your flows need some way to authenticate with any remote services they rely on. Most flows need, at a minimum, 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](https://ai.google.dev/available_regions). 2. [Generate an API key](https://aistudio.google.com/app/apikey) for the Gemini API using Google AI Studio. 3. Store your API key in Cloud Secret Manager: ```bash firebase functions:secrets:set GEMINI_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](https://firebase.google.com/docs/functions/config-env?gen=2nd#secret-manager) for more information on managing secrets. 4. Edit `src/index.ts` and add the following after the existing imports: ```ts import { defineSecret } from "firebase-functions/params"; const googleAIapiKey = defineSecret("GEMINI_API_KEY"); ``` Then, in the flow definition, declare that the cloud function needs access to this secret value: ```ts export const generatePoem = onCallGenkit( { secrets: [googleAIapiKey], }, generatePoemFlow ); ``` Now, when you deploy this function, your API key is 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](https://console.cloud.google.com/apis/library/aiplatform.googleapis.com?project=_) for your Firebase project. 2. On the [IAM](https://console.cloud.google.com/iam-admin/iam?project=_) 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. ### Add App Check enforcement [Section titled “Add App Check enforcement”](#add-app-check-enforcement) [Firebase App Check](https://firebase.google.com/docs/app-check) uses a built-in attestation mechanism to verify that your API is only being called by your application. `onCallGenkit` supports App Check enforcement declaratively. ```ts 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, ); ``` ### Set a CORS policy [Section titled “Set a CORS policy”](#set-a-cors-policy) Callable functions default to allowing any domain to call your function. If you want to customize the domains that can do this, use the `cors` option. With proper authentication (especially App Check), CORS is often unnecessary. ```ts export const generatePoem = onCallGenkit( { cors: 'mydomain.com', }, generatePoemFlow, ); ``` ### Complete example [Section titled “Complete example”](#complete-example) After you’ve made all of the changes described earlier, your deployable flow looks something like the following example: ```ts import { genkit } from 'genkit'; import { googleAI } from '@genkit-ai/googleai'; import { onCallGenkit, hasClaim } from 'firebase-functions/https'; import { defineSecret } from 'firebase-functions/params'; const apiKey = defineSecret('GEMINI_API_KEY'); const ai = genkit({ plugins: [googleAI()], model: googleAI.model('gemini-2.5-flash'), }); const generatePoemFlow = ai.defineFlow( { name: 'generatePoem', inputSchema: z.object({ subject: z.string() }), outputSchema: z.object({ poem: z.string() }), }, async ({ subject }) => { const { text } = await ai.generate(`Compose a poem about ${subject}.`); return { poem: text }; }, ); export const generatePoem = onCallGenkit( { secrets: [apiKey], authPolicy: hasClaim('email_verified'), enforceAppCheck: true, }, generatePoemFlow, ); ``` ## 3. Deploy flows to Firebase [Section titled “3. Deploy flows to Firebase”](#3-deploy-flows-to-firebase) After you’ve defined flows using `onCallGenkit`, you can deploy them the same way you would deploy other Cloud Functions: ```bash cd $PROJECT_ROOT firebase deploy --only functions ``` You’ve now deployed the flow as a Cloud Function! But you can’t access your deployed endpoint with `curl` or similar, because of the flow’s authorization policy. The next section explains how to securely access the flow. ## Optional: Try the deployed flow [Section titled “Optional: Try the deployed flow”](#optional-try-the-deployed-flow) To try out your flow endpoint, you can deploy the following minimal example web app: 1. In the [Project settings](https://console.firebase.google.com/project/_/settings/general) section of the Firebase console, add a new web app, selecting the option to also set up Hosting. 2. In the [Authentication](https://console.firebase.google.com/project/_/authentication/providers) section of the Firebase console, enable the **Google** provider, used in this example. 3. In your project directory, set up Firebase Hosting, where you will deploy the sample app: ```bash cd $PROJECT_ROOT firebase init hosting ``` Accept the defaults for all of the prompts. 4. Replace `public/index.html` with the following: ```html Genkit demo ``` 5. Deploy the web app and Cloud Function: ```bash 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. ## Optional: Run flows in the developer UI [Section titled “Optional: Run flows in the developer UI”](#optional-run-flows-in-the-developer-ui) You can run flows defined using `onCallGenkit` in the developer UI, exactly the same way as you run flows defined using `defineFlow`, so there’s no need to switch between the two between deployment and development. ```bash cd $PROJECT_ROOT/functions genkit start -- npx tsx --watch src/index.ts ``` or ```bash cd $PROJECT_ROOT/functions npm run genkit:start ``` You can now navigate to the URL printed by the `genkit start` command to access. ## Optional: Developing using Firebase Local Emulator Suite [Section titled “Optional: Developing using Firebase Local Emulator Suite”](#optional-developing-using-firebase-local-emulator-suite) Firebase offers a [suite of emulators for local development](https://firebase.google.com/docs/emulator-suite), which you can use with Genkit. To use the Genkit Dev UI with the Firebase Emulator Suite, start the Firebase emulators as follows: ```bash genkit start -- firebase emulators:start --inspect-functions ``` This command runs your code in the emulator, and runs the Genkit framework in development mode. This launches and exposes the Genkit reflection API (but not the Dev UI). # Use Genkit in a Next.js app > Learn how to integrate Genkit flows into your Next.js applications using the official Genkit Next.js plugin, covering project setup, flow definition, API routes, and client-side calls. This page shows how you can use Genkit flows in your Next.js applications using the official Genkit Next.js plugin. For complete API reference documentation, see the [Genkit Next.js Plugin API Reference](https://js.api.genkit.dev/modules/_genkit-ai_next.html). ## Before you begin [Section titled “Before you begin”](#before-you-begin) You should be familiar with Genkit’s concept of [flows](/docs/flows), and how to write them. ## Create a Next.js project [Section titled “Create a Next.js project”](#create-a-nextjs-project) If you don’t already have a Next.js project that you want to add generative AI features to, you can create one for the purpose of following along with this page: ```bash npx create-next-app@latest --src-dir ``` The `--src-dir` flag creates a `src/` directory to keep your project organized by separating source code from configuration files. ## Install Genkit dependencies [Section titled “Install Genkit dependencies”](#install-genkit-dependencies) Install the Genkit dependencies into your Next.js app: 1. Install the core Genkit library and the Next.js plugin: ```bash npm install genkit @genkit-ai/next ``` 2. Install at least one model plugin. * Gemini (Google AI) ```bash npm install @genkit-ai/googleai ``` * Gemini (Vertex AI) ```bash npm install @genkit-ai/vertexai ``` 3. Install the Genkit CLI globally. The tsx tool is also recommended as a development dependency, as it makes testing your code more convenient. Both of these dependencies are optional, however. ```bash npm install -g genkit-cli npm install --save-dev tsx ``` ## Define Genkit flows [Section titled “Define Genkit flows”](#define-genkit-flows) Create a new directory in your Next.js project to contain your Genkit flows. Create `src/genkit/` and add your flow definitions there: For example, create `src/genkit/menuSuggestionFlow.ts`: * Gemini (Google AI) ```ts import { googleAI } from '@genkit-ai/googleai'; import { genkit, z } from 'genkit'; const ai = genkit({ plugins: [googleAI()], }); export const menuSuggestionFlow = ai.defineFlow( { name: 'menuSuggestionFlow', inputSchema: z.object({ theme: z.string() }), outputSchema: z.object({ menuItem: z.string() }), streamSchema: z.string(), }, async ({ theme }, { sendChunk }) => { const { stream, response } = ai.generateStream({ model: googleAI.model('gemini-2.5-flash'), prompt: `Invent a menu item for a ${theme} themed restaurant.`, }); for await (const chunk of stream) { sendChunk(chunk.text); } const { text } = await response; return { menuItem: text }; } ); ``` * Gemini (Vertex AI) ```ts import { vertexAI } from '@genkit-ai/vertexai'; import { genkit, z } from 'genkit'; const ai = genkit({ plugins: [vertexAI()], }); export const menuSuggestionFlow = ai.defineFlow( { name: 'menuSuggestionFlow', inputSchema: z.object({ theme: z.string() }), outputSchema: z.object({ menuItem: z.string() }), streamSchema: z.string(), }, async ({ theme }, { sendChunk }) => { const { stream, response } = ai.generateStream({ model: vertexAI.model('gemini-2.5-flash'), prompt: `Invent a menu item for a ${theme} themed restaurant.`, }); for await (const chunk of stream) { sendChunk(chunk.text); } const { text } = await response; return { menuItem: text }; } ); ``` ## Create API routes [Section titled “Create API routes”](#create-api-routes) Now, create API routes that expose your flows using the Genkit Next.js plugin. For each flow, create a corresponding route file: Create `src/app/api/menuSuggestion/route.ts`: ```ts import { menuSuggestionFlow } from '@/genkit/menuSuggestionFlow'; import { appRoute } from '@genkit-ai/next'; export const POST = appRoute(menuSuggestionFlow); ``` ## Call your flows from the frontend [Section titled “Call your flows from the frontend”](#call-your-flows-from-the-frontend) In your frontend code, you can now call your flows using the Genkit Next.js client: ```tsx 'use client'; import { useState } from 'react'; import { runFlow, streamFlow } from '@genkit-ai/next/client'; import { menuSuggestionFlow } from '@/genkit/menuSuggestionFlow'; export default function Home() { const [menuItem, setMenuItem] = useState(''); const [isLoading, setIsLoading] = useState(false); const [streamedText, setStreamedText] = useState(''); async function getMenuItem(formData: FormData) { const theme = formData.get('theme')?.toString() ?? ''; setIsLoading(true); try { // Regular (non-streaming) approach const result = await runFlow({ url: '/api/menuSuggestion', input: { theme }, }); setMenuItem(result.menuItem); } catch (error) { console.error('Error generating menu item:', error); } finally { setIsLoading(false); } } async function streamMenuItem(formData: FormData) { const theme = formData.get('theme')?.toString() ?? ''; setIsLoading(true); setStreamedText(''); try { // Streaming approach const result = streamFlow({ url: '/api/menuSuggestion', input: { theme }, }); // Process the stream chunks as they arrive for await (const chunk of result.stream) { setStreamedText((prev) => prev + chunk); } // Get the final complete response const finalOutput = await result.output; setMenuItem(finalOutput.menuItem); } catch (error) { console.error('Error streaming menu item:', error); } finally { setIsLoading(false); } } return (



{streamedText && (

Streaming Output:

{streamedText}
)} {menuItem && (

Final Output:

{menuItem}
)}
); } ``` ## Authentication (Optional) [Section titled “Authentication (Optional)”](#authentication-optional) If you need to add authentication to your API routes, you can pass headers with your requests: ```tsx const result = await runFlow({ url: '/api/menuSuggestion', headers: { Authorization: 'Bearer your-token-here', }, input: { theme }, }); ``` ## Test your app locally [Section titled “Test your app locally”](#test-your-app-locally) If you want to run your app locally, you need to make credentials for the model API service you chose available. * Gemini (Google AI) 1. [Generate an API key](https://aistudio.google.com/app/apikey) for the Gemini API using Google AI Studio. 2. Set the `GEMINI_API_KEY` environment variable to your key: ```bash export GEMINI_API_KEY= ``` * Gemini (Vertex AI) 1. In the Cloud console, [Enable the Vertex AI API](https://console.cloud.google.com/apis/library/aiplatform.googleapis.com?project=_) for your project. 2. Configure the [`gcloud`](https://cloud.google.com/sdk/gcloud) tool to set up application default credentials: ```bash gcloud config set project gcloud services enable aiplatform.googleapis.com ``` Then, run your app locally as normal: ```bash npm run dev ``` For Genkit development tools, you can still use: ```bash genkit start -- npx tsx --watch src/genkit/menuSuggestionFlow.ts ``` ## Deploy your app [Section titled “Deploy your app”](#deploy-your-app) When you deploy your app, you will need to make sure the credentials for any external services you use (such as your chosen model API service) are available to the deployed app. See the following pages for information specific to your chosen deployment platform: * [Cloud Functions for Firebase](/docs/firebase) * [Cloud Run](/docs/cloud-run) * [Other Node.js platforms](/docs/deploy-node)