- Firebase Genkit
- When to use this skill
- AI workflow orchestration
-
- Building multi-step AI pipelines with type-safe inputs/outputs
- Flow-based APIs
-
- Wrapping LLM calls into deployable HTTP endpoints
- Tool calling / agents
-
- Equipping models with custom tools and implementing agentic loops
- RAG pipelines
-
- Retrieval-augmented generation with vector databases (Pinecone, pgvector, Firestore, Chroma, etc.)
- Multi-agent systems
-
- Coordinating multiple specialized AI agents
- Streaming responses
-
- Real-time token-by-token output for chat or long-form content
- Firebase/Cloud Run deployment
-
- Deploying AI functions to Google Cloud
- Prompt management
- Managing prompts as versioned .prompt files with Dotprompt Installation & Setup Step 1: Install the Genkit CLI
npm (recommended for JavaScript/TypeScript)
npm install -g genkit-cli
macOS/Linux binary
curl -sL cli.genkit.dev | bash Step 2: Create a TypeScript project mkdir my-genkit-app && cd my-genkit-app npm init -y npm pkg set type = module npm install -D typescript tsx npx tsc --init mkdir src && touch src/index.ts Step 3: Install Genkit core and a model plugin
Core + Google AI (Gemini) — free tier, no credit card required
npm install genkit @genkit-ai/google-genai
Or: Vertex AI (requires GCP project)
npm install genkit @genkit-ai/vertexai
Or: OpenAI
npm install genkit genkitx-openai
Or: Anthropic (Claude)
npm install genkit genkitx-anthropic
Or: Ollama (local models)
npm install genkit genkitx-ollama Step 4: Configure API Key
Google AI (Gemini)
export GEMINI_API_KEY = your_key_here
OpenAI
export OPENAI_API_KEY = your_key_here
Anthropic
export
ANTHROPIC_API_KEY
=
your_key_here
Core Concepts
Initializing Genkit
import
{
googleAI
}
from
'@genkit-ai/google-genai'
;
import
{
genkit
}
from
'genkit'
;
const
ai
=
genkit
(
{
plugins
:
[
googleAI
(
)
]
,
model
:
googleAI
.
model
(
'gemini-2.5-flash'
)
,
// default model
}
)
;
Defining Flows
Flows are the core primitive: type-safe, observable, deployable AI functions.
import
{
genkit
,
z
}
from
'genkit'
;
import
{
googleAI
}
from
'@genkit-ai/google-genai'
;
const
ai
=
genkit
(
{
plugins
:
[
googleAI
(
)
]
}
)
;
// Input/output schemas with Zod
const
SummaryInputSchema
=
z
.
object
(
{
text
:
z
.
string
(
)
.
describe
(
'Text to summarize'
)
,
maxWords
:
z
.
number
(
)
.
optional
(
)
.
default
(
100
)
,
}
)
;
const
SummaryOutputSchema
=
z
.
object
(
{
summary
:
z
.
string
(
)
,
keyPoints
:
z
.
array
(
z
.
string
(
)
)
,
}
)
;
export
const
summarizeFlow
=
ai
.
defineFlow
(
{
name
:
'summarizeFlow'
,
inputSchema
:
SummaryInputSchema
,
outputSchema
:
SummaryOutputSchema
,
}
,
async
(
{
text
,
maxWords
}
)
=>
{
const
{
output
}
=
await
ai
.
generate
(
{
model
:
googleAI
.
model
(
'gemini-2.5-flash'
)
,
prompt
:
Summarize the following text in at most
${
maxWords
}
words and extract key points:\n\n
${
text
}
,
output
:
{
schema
:
SummaryOutputSchema
}
,
}
)
;
if
(
!
output
)
throw
new
Error
(
'No output generated'
)
;
return
output
;
}
)
;
// Call the flow
const
result
=
await
summarizeFlow
(
{
text
:
'Long article content here...'
,
maxWords
:
50
,
}
)
;
console
.
log
(
result
.
summary
)
;
Generating Content
// Simple text generation
const
{
text
}
=
await
ai
.
generate
(
{
model
:
googleAI
.
model
(
'gemini-2.5-flash'
)
,
prompt
:
'Explain quantum computing in one sentence.'
,
}
)
;
// Structured output
const
{
output
}
=
await
ai
.
generate
(
{
prompt
:
'List 3 programming languages with their use cases'
,
output
:
{
schema
:
z
.
object
(
{
languages
:
z
.
array
(
z
.
object
(
{
name
:
z
.
string
(
)
,
useCase
:
z
.
string
(
)
,
}
)
)
,
}
)
,
}
,
}
)
;
// With system prompt
const
{
text
:
response
}
=
await
ai
.
generate
(
{
system
:
'You are a senior TypeScript engineer. Be concise.'
,
prompt
:
'What is the difference between interface and type in TypeScript?'
,
}
)
;
// Multimodal (image + text)
const
{
text
:
description
}
=
await
ai
.
generate
(
{
prompt
:
[
{
text
:
'What is in this image?'
}
,
{
media
:
{
url
:
'https://example.com/image.jpg'
,
contentType
:
'image/jpeg'
}
}
,
]
,
}
)
;
Streaming Flows
export
const
streamingFlow
=
ai
.
defineFlow
(
{
name
:
'streamingFlow'
,
inputSchema
:
z
.
object
(
{
topic
:
z
.
string
(
)
}
)
,
streamSchema
:
z
.
string
(
)
,
// type of each chunk
outputSchema
:
z
.
object
(
{
full
:
z
.
string
(
)
}
)
,
}
,
async
(
{
topic
}
,
{
sendChunk
}
)
=>
{
const
{
stream
,
response
}
=
ai
.
generateStream
(
{
prompt
:
Write a detailed essay about
${
topic
}
.
,
}
)
;
for
await
(
const
chunk
of
stream
)
{
sendChunk
(
chunk
.
text
)
;
// stream each token to client
}
const
{
text
}
=
await
response
;
return
{
full
:
text
}
;
}
)
;
// Client-side consumption
const
stream
=
streamingFlow
.
stream
(
{
topic
:
'AI ethics'
}
)
;
for
await
(
const
chunk
of
stream
.
stream
)
{
process
.
stdout
.
write
(
chunk
)
;
}
const
finalOutput
=
await
stream
.
output
;
Tool Calling (Agents)
import
{
z
}
from
'genkit'
;
// Define tools
const
getWeatherTool
=
ai
.
defineTool
(
{
name
:
'getWeather'
,
description
:
'Get current weather for a city'
,
inputSchema
:
z
.
object
(
{
city
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
object
(
{
temp
:
z
.
number
(
)
,
condition
:
z
.
string
(
)
}
)
,
}
,
async
(
{
city
}
)
=>
{
// Call real weather API
return
{
temp
:
22
,
condition
:
'sunny'
}
;
}
)
;
const
searchWebTool
=
ai
.
defineTool
(
{
name
:
'searchWeb'
,
description
:
'Search the web for information'
,
inputSchema
:
z
.
object
(
{
query
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
string
(
)
,
}
,
async
(
{
query
}
)
=>
{
// Call search API
return
Search results for:
${
query
}
;
}
)
;
// Agent flow with tools
export
const
agentFlow
=
ai
.
defineFlow
(
{
name
:
'agentFlow'
,
inputSchema
:
z
.
object
(
{
question
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
string
(
)
,
}
,
async
(
{
question
}
)
=>
{
const
{
text
}
=
await
ai
.
generate
(
{
prompt
:
question
,
tools
:
[
getWeatherTool
,
searchWebTool
]
,
returnToolRequests
:
false
,
// auto-execute tools
}
)
;
return
text
;
}
)
;
Prompts with Dotprompt
Manage prompts as versioned
.prompt
files:
src/prompts/summarize.prompt
model: googleai/gemini-2.5-flash input: schema: text: string style?: string output: schema: summary: string sentiment: string
Summarize the following text in a {{style, default: "professional"}} tone:
{{text}}
Return JSON with summary and sentiment (positive/negative/neutral).
// Load and use dotprompt
const
summarizePrompt
=
ai
.
prompt
(
'summarize'
)
;
const
{
output
}
=
await
summarizePrompt
(
{
text
:
'Article content here...'
,
style
:
'casual'
,
}
)
;
RAG — Retrieval-Augmented Generation
import
{
devLocalVectorstore
}
from
'@genkit-ai/dev-local-vectorstore'
;
import
{
textEmbedding004
}
from
'@genkit-ai/google-genai'
;
const
ai
=
genkit
(
{
plugins
:
[
googleAI
(
)
,
devLocalVectorstore
(
[
{
indexName
:
'documents'
,
embedder
:
textEmbedding004
,
}
]
)
,
]
,
}
)
;
// Index documents
await
ai
.
index
(
{
indexer
:
devLocalVectorstoreIndexer
(
'documents'
)
,
docs
:
[
{
content
:
[
{
text
:
'Document 1 content...'
}
]
,
metadata
:
{
source
:
'doc1'
}
}
,
{
content
:
[
{
text
:
'Document 2 content...'
}
]
,
metadata
:
{
source
:
'doc2'
}
}
,
]
,
}
)
;
// RAG flow
export
const
ragFlow
=
ai
.
defineFlow
(
{
name
:
'ragFlow'
,
inputSchema
:
z
.
object
(
{
question
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
string
(
)
,
}
,
async
(
{
question
}
)
=>
{
// Retrieve relevant documents
const
docs
=
await
ai
.
retrieve
(
{
retriever
:
devLocalVectorstoreRetriever
(
'documents'
)
,
query
:
question
,
options
:
{
k
:
3
}
,
}
)
;
// Generate answer grounded in retrieved docs
const
{
text
}
=
await
ai
.
generate
(
{
system
:
'Answer questions using only the provided context.'
,
prompt
:
question
,
docs
,
}
)
;
return
text
;
}
)
;
Chat Sessions
export
const
chatFlow
=
ai
.
defineFlow
(
{
name
:
'chatFlow'
,
inputSchema
:
z
.
object
(
{
message
:
z
.
string
(
)
,
sessionId
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
string
(
)
,
}
,
async
(
{
message
,
sessionId
}
)
=>
{
const
session
=
ai
.
loadSession
(
sessionId
)
??
ai
.
createSession
(
{
sessionId
}
)
;
const
chat
=
session
.
chat
(
{
system
:
'You are a helpful assistant.'
,
}
)
;
const
{
text
}
=
await
chat
.
send
(
message
)
;
return
text
;
}
)
;
Multi-Agent Systems
// Specialist agents
const
researchAgent
=
ai
.
defineFlow
(
{
name
:
'researchAgent'
,
inputSchema
:
z
.
string
(
)
,
outputSchema
:
z
.
string
(
)
}
,
async
(
query
)
=>
{
const
{
text
}
=
await
ai
.
generate
(
{
system
:
'You are a research expert. Gather facts and cite sources.'
,
prompt
:
query
,
tools
:
[
searchWebTool
]
,
}
)
;
return
text
;
}
)
;
const
writerAgent
=
ai
.
defineFlow
(
{
name
:
'writerAgent'
,
inputSchema
:
z
.
string
(
)
,
outputSchema
:
z
.
string
(
)
}
,
async
(
brief
)
=>
{
const
{
text
}
=
await
ai
.
generate
(
{
system
:
'You are a professional writer. Write clear, engaging content.'
,
prompt
:
brief
,
}
)
;
return
text
;
}
)
;
// Orchestrator delegates to specialists
export
const
contentPipelineFlow
=
ai
.
defineFlow
(
{
name
:
'contentPipelineFlow'
,
inputSchema
:
z
.
object
(
{
topic
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
string
(
)
,
}
,
async
(
{
topic
}
)
=>
{
const
research
=
await
researchAgent
(
Research:
${
topic
}
)
;
const
article
=
await
writerAgent
(
Write an article based on:
${
research
}
)
;
return
article
;
}
)
;
Developer Tools
CLI Commands
Start Developer UI + connect to your app
genkit start -- npx tsx --watch src/index.ts genkit start -o -- npx tsx src/index.ts
auto-open browser
Run a specific flow from CLI
genkit flow:run summarizeFlow '{"text": "Hello world", "maxWords": 10}'
Run with streaming output
genkit flow:run streamingFlow '{"topic": "AI"}' -s
Evaluate a flow
genkit eval:flow ragFlow --input eval-inputs.json
View all commands
genkit --help
Disable analytics telemetry
- genkit config
- set
- analyticsOptOut
- true
- Developer UI
- The Developer UI runs at
- http://localhost:4000
- and provides:
- Flow runner
-
- Execute flows with custom JSON inputs
- Trace inspector
-
- Visualize each step (generate, embed, retrieve, tool calls)
- Prompt playground
-
- Test prompts interactively
- Model tester
-
- Compare outputs across different models
- Evaluator
- Run evaluation datasets against flows
Add npm script for convenience
package.json
"scripts" : { "genkit:dev" : "genkit start -- npx tsx --watch src/index.ts" } npm run genkit:dev Deployment Firebase Cloud Functions import { onCallGenkit } from 'firebase-functions/https' ; import { defineSecret } from 'firebase-functions/params' ; const apiKey = defineSecret ( 'GOOGLE_AI_API_KEY' ) ; export const summarize = onCallGenkit ( { secrets : [ apiKey ] } , summarizeFlow ) ; firebase deploy --only functions Express.js Server import express from 'express' ; import { expressHandler } from 'genkit/express' ; const app = express ( ) ; app . use ( express . json ( ) ) ; app . post ( '/summarize' , expressHandler ( summarizeFlow ) ) ; app . post ( '/chat' , expressHandler ( chatFlow ) ) ; app . listen ( 3000 , ( ) => console . log ( 'Server running on port 3000' ) ) ; Cloud Run
Build and deploy
gcloud run deploy genkit-app
\
--source
.
\
--region
us-central1
\
--set-env-vars
GEMINI_API_KEY
=
$GEMINI_API_KEY
Supported Plugins
Model Providers
Plugin
Package
Models
Google AI
@genkit-ai/google-genai
Gemini 2.5 Flash/Pro
Vertex AI
@genkit-ai/vertexai
Gemini, Imagen, Claude
OpenAI
genkitx-openai
GPT-4o, o1, etc.
Anthropic
genkitx-anthropic
Claude 3.5/3
AWS Bedrock
genkitx-aws-bedrock
Claude, Titan, etc.
Ollama
genkitx-ollama
Local models
DeepSeek
genkitx-deepseek
DeepSeek-R1
xAI (Grok)
genkitx-xai
Grok models
Vector Databases
Plugin
Package
Dev Local (testing)
@genkit-ai/dev-local-vectorstore
Pinecone
genkitx-pinecone
pgvector
genkitx-pgvector
Chroma
genkitx-chroma
Cloud Firestore
@genkit-ai/firebase
LanceDB
genkitx-lancedb
Best Practices
Always define input/output schemas
— Use Zod objects for Dev UI labeled fields and API safety
Use flows for all AI logic
— Even simple calls; flows give you tracing and deployment for free
Store API keys in environment variables
— Never hardcode; use Firebase Secrets for production
Use
ai.run()
to trace custom steps
— Wrap non-Genkit code in
ai.run()
for trace visibility
Stream long-form content
— Use
defineFlow
with
streamSchema
+
sendChunk
for better UX
Separate concerns with agents
— Specialized subflows > one monolithic flow
Use Dotprompt for team prompts
—
.prompt
files enable versioning, review, and reuse
Constraints
Must Do
Define schemas for all flow inputs and outputs
Handle
null
output from
generate()
— throw meaningful errors
Set
GENKIT_ENV=dev
when running flows separately from the dev server
Use
onCallGenkit
(not raw Cloud Functions) when deploying to Firebase
Must Not Do
Never hardcode API keys in source code
Do not use
generate()
outside a flow if you need tracing/observability
Do not call
genkit start
without a command — always pass
-- Say hello to
${
name
}
in a creative way.
)
;
return
text
;
}
)
;
// Run it
const
greeting
=
await
helloFlow
(
{
name
:
'World'
}
)
;
console
.
log
(
greeting
)
;
Example 2: Full RAG + Agent Pipeline
import
{
googleAI
,
textEmbedding004
}
from
'@genkit-ai/google-genai'
;
import
{
devLocalVectorstore
}
from
'@genkit-ai/dev-local-vectorstore'
;
import
{
genkit
,
z
}
from
'genkit'
;
const
ai
=
genkit
(
{
plugins
:
[
googleAI
(
)
,
devLocalVectorstore
(
[
{
indexName
:
'kb'
,
embedder
:
textEmbedding004
}
]
)
,
]
,
}
)
;
// Index knowledge base documents
const
indexKnowledgeBase
=
ai
.
defineFlow
(
{
name
:
'indexKB'
,
inputSchema
:
z
.
array
(
z
.
string
(
)
)
}
,
async
(
texts
)
=>
{
await
ai
.
index
(
{
indexer
:
devLocalVectorstoreIndexer
(
'kb'
)
,
docs
:
texts
.
map
(
text
=>
(
{
content
:
[
{
text
}
]
}
)
)
,
}
)
;
}
)
;
// Answer questions using RAG
export
const
answerFlow
=
ai
.
defineFlow
(
{
name
:
'answerFlow'
,
inputSchema
:
z
.
object
(
{
question
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
object
(
{
answer
:
z
.
string
(
)
,
sources
:
z
.
number
(
)
}
)
,
}
,
async
(
{
question
}
)
=>
{
const
docs
=
await
ai
.
retrieve
(
{
retriever
:
devLocalVectorstoreRetriever
(
'kb'
)
,
query
:
question
,
options
:
{
k
:
5
}
,
}
)
;
const
{
text
}
=
await
ai
.
generate
(
{
system
:
'Answer only from the provided context. If unsure, say so.'
,
prompt
:
question
,
docs
,
}
)
;
return
{
answer
:
text
,
sources
:
docs
.
length
}
;
}
)
;
Example 3: Multi-Model Comparison
import
{
googleAI
}
from
'@genkit-ai/google-genai'
;
import
{
openAI
}
from
'genkitx-openai'
;
import
{
genkit
,
z
}
from
'genkit'
;
const
ai
=
genkit
(
{
plugins
:
[
googleAI
(
)
,
openAI
(
)
]
}
)
;
export
const
compareModelsFlow
=
ai
.
defineFlow
(
{
name
:
'compareModelsFlow'
,
inputSchema
:
z
.
object
(
{
prompt
:
z
.
string
(
)
}
)
,
outputSchema
:
z
.
object
(
{
gemini
:
z
.
string
(
)
,
gpt4o
:
z
.
string
(
)
}
)
,
}
,
async
(
{
prompt
}
)
=>
{
const
[
geminiResult
,
gptResult
]
=
await
Promise
.
all
(
[
ai
.
generate
(
{
model
:
googleAI
.
model
(
'gemini-2.5-flash'
)
,
prompt
}
)
,
ai
.
generate
(
{
model
:
'openai/gpt-4o'
,
prompt
}
)
,
]
)
;
return
{
gemini
:
geminiResult
.
text
,
gpt4o
:
gptResult
.
text
,
}
;
}
)
;