Use Genkit in an Angular app
This page shows how you can use Genkit flows in Angular apps.
Before you begin
Section titled “Before you begin”You should be familiar with Genkit’s concept of flows, and how to write them.
Create an Angular project
Section titled “Create an Angular project”This guide will use an Angular app with SSR with server routing.
You can create a new project with server-side routing with the Angular CLI:
ng new --ssr --server-routing
You can also add server-side routing to an existing project with the ng add
command:
ng add @angular/ssr --server-routing
Install Genkit dependencies
Section titled “Install Genkit dependencies”Install the Genkit dependencies into your Angular app:
-
Install the core Genkit library:
Terminal window npm install genkit -
Install at least one model plugin.
For example, to use Google AI:
Terminal window npm install @genkit-ai/googleaiOr to use Vertex AI:
Terminal window npm install @genkit-ai/vertexai -
Install the Genkit Express library:
Terminal window npm install @genkit-ai/express -
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.
Terminal window npm install -g genkit-clinpm install --save-dev tsx
Define Genkit flows
Section titled “Define Genkit flows”Create a new directory in your Angular project to contain your Genkit flows. Create src/genkit/
and add your flow definitions there:
For example, create src/genkit/menuSuggestionFlow.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.0-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 }; });
Add server routes
Section titled “Add server routes”Add the following imports to src/server.ts
:
import { expressHandler } from '@genkit-ai/express';import { menuSuggestionFlow } from './genkit/menuSuggestionFlow';
Add the following line following your app
variable initialization:
app.use(express.json());
Then, add a route to serve your flow:
app.post('/api/menuSuggestion', expressHandler(menuSuggestionFlow));
Call your flows from the frontend
Section titled “Call your flows from the frontend”In your frontend code, you can now call your flows using the Genkit client library. You can use both non-streaming and streaming approaches:
Non-streaming Flow Calls
Section titled “Non-streaming Flow Calls”Replace the contents of src/app/app.component.ts
with the following:
import { Component, resource, signal } from '@angular/core';import { FormsModule } from '@angular/forms';import { runFlow } from 'genkit/beta/client';
@Component({ selector: 'app-root', imports: [FormsModule], templateUrl: './app.component.html',})export class AppComponent { menuInput = ''; theme = signal('');
menuResource = resource({ request: () => this.theme(), loader: ({ request }) => runFlow({ url: 'http://localhost:4200/api/menuSuggestion', input: { theme: request } }), });}
Make corresponding updates to src/app/app.component.html
:
<main> <h3>Generate a custom menu item</h3> <label for="theme">Suggest a menu item for a restaurant with this theme: </label> <input type="text" id="theme" [(ngModel)]="menuInput" /> <button (click)="theme.set(menuInput)">Generate</button> <br /> <br /> @if (menuResource.isLoading()) { <div>Loading...</div> } @else if (menuResource.value()) { <div> <h4>Generated Menu Item:</h4> <pre>{{ menuResource.value().menuItem }}</pre> </div> }</main>
Streaming Flow Calls
Section titled “Streaming Flow Calls”For streaming responses, you can extend your component:
import { Component, resource, signal } from '@angular/core';import { FormsModule } from '@angular/forms';import { runFlow, streamFlow } from 'genkit/beta/client';
@Component({ selector: 'app-root', imports: [FormsModule], templateUrl: './app.component.html',})export class AppComponent { menuInput = ''; theme = signal(''); streamedText = signal(''); isStreaming = signal(false);
menuResource = resource({ request: () => this.theme(), loader: ({ request }) => runFlow({ url: 'http://localhost:4200/api/menuSuggestion', input: { theme: request } }), });
async streamMenuItem() { const theme = this.menuInput; if (!theme) return;
this.isStreaming.set(true); this.streamedText.set('');
try { const result = streamFlow({ url: 'http://localhost:4200/api/menuSuggestion', input: { theme }, });
// Process the stream chunks as they arrive for await (const chunk of result.stream) { this.streamedText.update(prev => prev + chunk); }
// Get the final complete response const finalOutput = await result.output; console.log('Final output:', finalOutput); } catch (error) { console.error('Error streaming menu item:', error); } finally { this.isStreaming.set(false); } }}
And update the template to include streaming:
<main> <h3>Generate a custom menu item</h3> <label for="theme">Suggest a menu item for a restaurant with this theme: </label> <input type="text" id="theme" [(ngModel)]="menuInput" /> <br /> <br /> <button (click)="theme.set(menuInput)" [disabled]="menuResource.isLoading()"> Generate </button> <button (click)="streamMenuItem()" [disabled]="isStreaming()"> Stream Generation </button> <br />
@if (streamedText()) { <div> <h4>Streaming Output:</h4> <pre>{{ streamedText() }}</pre> </div> }
@if (menuResource.isLoading()) { <div>Loading...</div> } @else if (menuResource.value()) { <div> <h4>Generated Menu Item:</h4> <pre>{{ menuResource.value().menuItem }}</pre> </div> }
@if (isStreaming()) { <div>Streaming...</div> }</main>
Authentication (Optional)
Section titled “Authentication (Optional)”If you need to add authentication to your API routes, you can pass headers with your requests:
menuResource = resource({ request: () => this.theme(), loader: ({ request }) => runFlow({ url: 'http://localhost:4200/api/menuSuggestion', headers: { Authorization: 'Bearer your-token-here', }, input: { theme: request } }),});
Test your app locally
Section titled “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.
-
Generate an API key for the Gemini API using Google AI Studio.
-
Set the
GEMINI_API_KEY
environment variable to your key:Terminal window export GEMINI_API_KEY=<your API key>
-
In the Cloud console, Enable the Vertex AI API for your project.
-
Set some environment variables and use the
gcloud
tool to set up application default credentials:Terminal window export GCLOUD_PROJECT=<your project ID>export GCLOUD_LOCATION=us-central1gcloud auth application-default login
Then, run your app locally as normal:
ng serve
All of Genkit’s development tools continue to work as normal. For example, to load your flows in the developer UI:
genkit start -- npx tsx --watch src/genkit/menuSuggestionFlow.ts
Deploy your app
Section titled “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:
Next steps
Section titled “Next steps”- Explore Genkit in a deployed Angular app: Walk through a reference implementation of multiple Genkit flows powering an Angular app, and then jump into the code in Firebase Studio.