Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/firebase/genkit/llms.txt

Use this file to discover all available pages before exploring further.

Plugins are Genkit’s primary extension mechanism. They add new capabilities like model providers, telemetry backends, vector stores, and custom actions.

What are Plugins?

A plugin extends Genkit by registering new actions (models, tools, retrievers, etc.) and providing configuration for external services. Plugins can:
  • Provide AI models: Gemini, Claude, GPT, Llama, etc.
  • Add telemetry: Cloud Trace, Datadog, Sentry, etc.
  • Enable vector search: Pinecone, Chroma, Vertex AI Vector Search
  • Add safety checks: Content filtering, PII detection
  • Integrate frameworks: Express, Flask, FastAPI
  • Register custom tools: Any function you want models to call

Using Plugins

import { genkit } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
import { googleCloud } from '@genkit-ai/google-cloud';

const ai = genkit({
  plugins: [
    googleAI(),              // Gemini models
    googleCloud(),           // Cloud Trace + Logging
  ],
});

Plugin Architecture

All plugins implement the same interface:
class Plugin:
    """Base class for all Genkit plugins."""
    
    name: str  # Plugin namespace (e.g., 'googleai', 'anthropic')
    
    async def init(self) -> list[Action]:
        """One-time initialization. Returns actions to pre-register.
        
        Called lazily on first action resolution, NOT at registration.
        """
        ...
    
    async def resolve(self, kind: ActionKind, name: str) -> Action | None:
        """Resolve a single action by kind and name.
        
        Returns None if this plugin doesn't handle the requested action.
        Called for each action lookup.
        """
        ...
    
    async def list_actions(self) -> list[ActionMetadata]:
        """List available actions without heavy initialization.
        
        Called by the Reflection API for DevUI action discovery.
        Must be fast and not trigger expensive operations.
        """
        ...

Plugin Lifecycle

Plugins follow a four-phase lifecycle:

1. Registration

Plugins are registered when you create a Genkit instance:
ai = Genkit(
    plugins=[GoogleGenAI(), Anthropic()]
)
# Plugins are stored but NOT initialized yet

2. Lazy Initialization

Plugins are initialized only when first used:
# This triggers GoogleAI plugin initialization
response = await ai.generate(
    model='googleai/gemini-2.0-flash',
    prompt='Hello!',
)
On first use:
  1. Registry calls plugin.init()
  2. Plugin returns pre-registered actions
  3. Actions are cached in registry
  4. Subsequent calls use cached actions (no re-init)

3. Action Resolution

When you reference an action by name:
# "googleai/gemini-2.0-flash" triggers resolution
response = await ai.generate(
    model='googleai/gemini-2.0-flash',
    prompt='Hello!',
)
Resolution flow:
  1. Check cache - already resolved?
  2. If namespaced (googleai/...), find that plugin
  3. Call plugin.resolve(ActionKind.MODEL, 'googleai/gemini-2.0-flash')
  4. Cache and return the action

4. Action Discovery

The Developer UI queries plugins without initializing them:
# DevUI calls this on all plugins
actions = await plugin.list_actions()
# Returns metadata: names, types, descriptions
# Does NOT trigger init() - must be fast

Official Plugins

Model Providers

PluginModelsInstallation
Google AIGemini, Imagen, Veo, Lyria, TTSnpm i @genkit-ai/google-genai
pip install genkit[google-genai]
AnthropicClaude 3.5 Sonnet, Claude 3 Opusnpm i @genkit-ai/anthropic
pip install genkit[anthropic]
Vertex AIModel Garden (1000+ models)npm i @genkit-ai/vertexai
pip install genkit[vertexai]
OllamaLlama, Mistral, CodeLlama (local)npm i @genkit-ai/ollama
pip install genkit[ollama]
OpenAI-compatibleAny OpenAI-compatible APInpm i @genkit-ai/compat-oai
pip install genkit[compat-oai]
Mistral AIMistral, Mixtral modelsnpm i @genkit-ai/mistral
pip install genkit[mistral]
DeepSeekDeepSeek modelsnpm i @genkit-ai/deepseek
pip install genkit[deepseek]
xAIGrok modelsnpm i @genkit-ai/xai
pip install genkit[xai]

Telemetry & Observability

PluginPurposeInstallation
Google CloudCloud Trace + Cloud Loggingnpm i @genkit-ai/google-cloud
pip install genkit[google-cloud]
FirebaseFirebase telemetry + Authnpm i @genkit-ai/firebase
pip install genkit[firebase]
ObservabilitySentry, Datadog, Honeycombnpm i @genkit-ai/observability
pip install genkit[observability]

Vector Stores

PluginPurposeInstallation
Vertex AI Vector SearchProduction vector DBnpm i @genkit-ai/vertexai
pip install genkit[vertexai]
PineconeVector searchnpm i @genkit-ai/pinecone
ChromaLocal vector DBnpm i @genkit-ai/chroma
Dev Local Vector StoreDevelopment/testingnpm i @genkit-ai/dev-local-vectorstore
pip install genkit[dev-local-vectorstore]

Safety & Evaluation

PluginPurposeInstallation
ChecksContent safety guardrailsnpm i @genkit-ai/checks
pip install genkit[checks]
EvaluatorsRAGAS metrics, custom evalsnpm i @genkit-ai/evaluators
pip install genkit[evaluators]

Framework Integration

PluginPurposeInstallation
ExpressNode.js HTTP servernpm i @genkit-ai/express
FlaskPython HTTP serverpip install genkit[flask]
Next.jsNext.js integrationnpm i @genkit-ai/next

Community Plugins

Community-maintained plugins (best-effort support):
  • Amazon Bedrock: Claude, Llama, Titan + AWS X-Ray telemetry
  • Azure AI: Azure Monitor telemetry
  • Cloudflare Workers AI: Edge AI models + OTLP telemetry
  • Cohere: Command models + reranking
  • HuggingFace: Inference API models
  • Microsoft Foundry: Azure AI Foundry (11,000+ models)

Plugin Configuration

Most plugins accept configuration options:
import { googleAI } from '@genkit-ai/google-genai';

const ai = genkit({
  plugins: [
    googleAI({
      apiKey: process.env.GOOGLE_API_KEY,
      apiVersion: 'v1beta',
    }),
  ],
});

Environment Variables

Most plugins support environment variable configuration:
# Google AI
export GOOGLE_API_KEY=your-api-key

# Anthropic
export ANTHROPIC_API_KEY=your-api-key

# OpenAI-compatible
export OPENAI_API_KEY=your-api-key
export OPENAI_BASE_URL=https://api.openai.com/v1

Creating Custom Plugins

Basic Plugin

Create a custom plugin to add your own models or tools:
from genkit.core.plugin import Plugin
from genkit.core.action import Action, ActionMetadata
from genkit.core.action.types import ActionKind

class MyPlugin(Plugin):
    """Custom plugin example."""
    
    name = 'myplugin'
    
    def __init__(self, api_key: str):
        self.api_key = api_key
    
    async def init(self) -> list[Action]:
        """Return actions to pre-register (optional)."""
        return []
    
    async def resolve(self, kind: ActionKind, name: str) -> Action | None:
        """Resolve actions on-demand."""
        if kind == ActionKind.MODEL:
            if name == 'myplugin/my-model':
                return self._create_model(name)
        return None
    
    async def list_actions(self) -> list[ActionMetadata]:
        """List available actions for DevUI."""
        return [
            ActionMetadata(
                kind=ActionKind.MODEL,
                name='myplugin/my-model',
                description='My custom model',
            ),
        ]
    
    def _create_model(self, name: str) -> Action:
        """Create model action."""
        # Define your model implementation...
        ...

# Usage
ai = Genkit(plugins=[MyPlugin(api_key='...')])
response = await ai.generate(
    model='myplugin/my-model',
    prompt='Hello!',
)

Plugin with Multiple Action Types

class AdvancedPlugin(Plugin):
    name = 'advanced'
    
    async def resolve(self, kind: ActionKind, name: str) -> Action | None:
        # Handle different action types
        if kind == ActionKind.MODEL:
            return self._resolve_model(name)
        elif kind == ActionKind.EMBEDDER:
            return self._resolve_embedder(name)
        elif kind == ActionKind.RETRIEVER:
            return self._resolve_retriever(name)
        return None
    
    def _resolve_model(self, name: str) -> Action | None:
        if name == 'advanced/my-model':
            return self._create_model()
        return None
    
    def _resolve_embedder(self, name: str) -> Action | None:
        if name == 'advanced/embedder':
            return self._create_embedder()
        return None
    
    def _resolve_retriever(self, name: str) -> Action | None:
        if name == 'advanced/retriever':
            return self._create_retriever()
        return None

Plugin Namespaces

Each plugin has a namespace that prefixes its actions:
[plugin-namespace]/[action-name]
Examples:
  • googleai/gemini-2.0-flash - plugin: googleai, model: gemini-2.0-flash
  • anthropic/claude-3-5-sonnet - plugin: anthropic, model: claude-3-5-sonnet
  • myplugin/my-model - plugin: myplugin, model: my-model
Namespaces prevent conflicts between plugins that might have similarly named actions.

Plugin Discovery

The Developer UI uses list_actions() to discover available actions:
class MyPlugin(Plugin):
    async def list_actions(self) -> list[ActionMetadata]:
        """Fast listing without initialization."""
        return [
            ActionMetadata(
                kind=ActionKind.MODEL,
                name='myplugin/model-1',
                description='First model',
            ),
            ActionMetadata(
                kind=ActionKind.MODEL,
                name='myplugin/model-2',
                description='Second model',
            ),
            ActionMetadata(
                kind=ActionKind.TOOL,
                name='myplugin/my-tool',
                description='Custom tool',
            ),
        ]
Important:
  • list_actions() must be fast - no expensive operations
  • Does NOT trigger init() - plugins remain uninitialized
  • Only returns metadata, not full action objects

Dynamic Action Providers

For actions that are discovered at runtime (like MCP servers):
from genkit.core.registry import DynamicActionProvider

class MCPPlugin(Plugin, DynamicActionProvider):
    """Plugin that discovers tools at runtime."""
    
    name = 'mcp'
    
    async def discover_tools(self) -> list[Action]:
        """Called when registry can't find an action."""
        # Connect to MCP server, get available tools
        tools = await self.mcp_client.list_tools()
        return [self._tool_to_action(t) for t in tools]

Combining Multiple Plugins

Use multiple plugins together:
from genkit import Genkit
from genkit.plugins.google_genai import GoogleGenAI
from genkit.plugins.anthropic import Anthropic
from genkit.plugins.google_cloud import GoogleCloud
from genkit.plugins.pinecone import Pinecone

ai = Genkit(
    plugins=[
        # Model providers
        GoogleGenAI(),
        Anthropic(),
        
        # Telemetry
        GoogleCloud(),
        
        # Vector store
        Pinecone(api_key='...', environment='...'),
    ],
)

# Use Gemini for chat
response = await ai.generate(
    model='googleai/gemini-2.0-flash',
    prompt='Hello!',
)

# Use Claude for analysis
analysis = await ai.generate(
    model='anthropic/claude-3-5-sonnet',
    prompt='Analyze this text...',
)

# Use Pinecone for retrieval
results = await ai.retrieve(
    retriever='pinecone/my-index',
    query='quantum computing',
)

Plugin Best Practices

1. Lazy Initialization

Defer expensive operations to init(), not __init__():
class MyPlugin(Plugin):
    def __init__(self, api_key: str):
        # Fast - just store config
        self.api_key = api_key
        self.client = None  # Don't create yet!
    
    async def init(self) -> list[Action]:
        # Expensive - only when first used
        self.client = await create_api_client(self.api_key)
        return []

2. Fast Action Listing

list_actions() must be fast - no API calls:
class MyPlugin(Plugin):
    async def list_actions(self) -> list[ActionMetadata]:
        # Good - static list
        return [
            ActionMetadata(kind=ActionKind.MODEL, name='myplugin/model-1'),
            ActionMetadata(kind=ActionKind.MODEL, name='myplugin/model-2'),
        ]
    
    # Bad - don't do this in list_actions()!
    # await self.api.get_available_models()  # Too slow!

3. Graceful Degradation

Handle missing API keys gracefully:
class MyPlugin(Plugin):
    def __init__(self, api_key: str | None = None):
        self.api_key = api_key or os.getenv('MY_PLUGIN_API_KEY')
    
    async def init(self) -> list[Action]:
        if not self.api_key:
            logger.warning('MY_PLUGIN_API_KEY not set - plugin disabled')
            return []
        # Continue initialization...

4. Clear Error Messages

Provide helpful errors when things go wrong:
async def resolve(self, kind: ActionKind, name: str) -> Action | None:
    if kind == ActionKind.MODEL:
        if not self.api_key:
            raise GenkitError(
                status='FAILED_PRECONDITION',
                message=f'Cannot use {name}: MY_PLUGIN_API_KEY not configured. '
                        f'Set environment variable or pass api_key to plugin.',
            )

Example: Complete Custom Plugin

A complete weather plugin:
import httpx
from genkit.core.plugin import Plugin
from genkit.core.action import Action, ActionMetadata
from genkit.core.action.types import ActionKind
from pydantic import BaseModel

class WeatherResult(BaseModel):
    temperature: float
    conditions: str
    humidity: float

class WeatherPlugin(Plugin):
    """Provides weather data via API."""
    
    name = 'weather'
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.client = None
    
    async def init(self) -> list[Action]:
        """Initialize HTTP client."""
        self.client = httpx.AsyncClient(
            base_url='https://api.weather.example.com',
            headers={'Authorization': f'Bearer {self.api_key}'},
        )
        return []
    
    async def resolve(self, kind: ActionKind, name: str) -> Action | None:
        """Resolve weather tools."""
        if kind == ActionKind.TOOL:
            if name == 'weather/get-current':
                return self._create_get_current_tool()
            elif name == 'weather/get-forecast':
                return self._create_get_forecast_tool()
        return None
    
    async def list_actions(self) -> list[ActionMetadata]:
        """List available weather tools."""
        return [
            ActionMetadata(
                kind=ActionKind.TOOL,
                name='weather/get-current',
                description='Get current weather for a city',
            ),
            ActionMetadata(
                kind=ActionKind.TOOL,
                name='weather/get-forecast',
                description='Get weather forecast for a city',
            ),
        ]
    
    def _create_get_current_tool(self) -> Action:
        """Create the get-current-weather tool."""
        async def get_current(city: str) -> WeatherResult:
            response = await self.client.get(f'/current?city={city}')
            data = response.json()
            return WeatherResult(
                temperature=data['temp'],
                conditions=data['conditions'],
                humidity=data['humidity'],
            )
        
        return Action(
            name='weather/get-current',
            kind=ActionKind.TOOL,
            fn=get_current,
        )

# Usage
ai = Genkit(plugins=[WeatherPlugin(api_key='your-key')])

response = await ai.generate(
    prompt='What is the weather in Tokyo?',
    tools=['weather/get-current'],
)

Next Steps

Build docs developers (and LLMs) love