Skip to content

Creating Genkit Plugins

Genkit’s capabilities are designed to be extended by plugins. Genkit plugins are configurable modules that can provide models, retrievers, trace stores, and more. You’ve already seen plugins in action just by using Genkit:

import (
"[github.com/firebase/genkit/go/ai](https://github.com/firebase/genkit/go/ai)"
"[github.com/firebase/genkit/go/genkit](https://github.com/firebase/genkit/go/genkit)"
"[github.com/firebase/genkit/go/plugins/googlegenai](https://github.com/firebase/genkit/go/plugins/googlegenai)"
"[github.com/firebase/genkit/go/plugins/server](https://github.com/firebase/genkit/go/plugins/server)"
)
g, err := genkit.Init(ctx,
ai.WithPlugins(
&googlegenai.GoogleAI{APIKey: ...},
&googlegenai.VertexAI{ProjectID: "my-project", Location: "us-central1"},
),
)

The Vertex AI plugin takes configuration (such as the user’s Google Cloud project ID) and registers a variety of new models, embedders, and more with the Genkit registry. The registry serves as a lookup service for named actions at runtime, and powers Genkit’s local UI for running and inspecting models, prompts, and more.

In Go, a Genkit plugin is a package that adheres to a small set of conventions. A single module can contain several plugins.

Every plugin must have a unique identifier string that distinguishes it from other plugins. Genkit uses this identifier as a namespace for every resource your plugin defines, to prevent naming conflicts with other plugins.

For example, if your plugin has an ID yourplugin and provides a model called text-generator, the full model identifier will be yourplugin/text-generator.

This provider ID needs to be exported and you should define it once for your plugin and use it consistently when required by a Genkit function.

package yourplugin
const providerID = "yourplugin"

Every plugin should define and export the following symbols to conform to the genkit.Plugin interface:

  • A struct type that encapsulates all of the configuration options accepted by the plugin.

    For any plugin options that are secret values, such as API keys, you should offer both a config option and a default environment variable to configure it. This lets your plugin take advantage of the secret-management features offered by many hosting providers (such as Cloud Secret Manager, which you can use with Cloud Run). For example:

    type MyPlugin struct {
    APIKey string
    // Other options you may allow to configure...
    }
  • A Name() method on the struct that returns the provider ID.

  • An Init() method on the struct with a declaration like the following:

    func (m *MyPlugin) Init(ctx context.Context, g *genkit.Genkit) error

    In this function, perform any setup steps required by your plugin. For example:

    • Confirm that any required configuration values are specified and assign default values to any unspecified optional settings.
    • Verify that the given configuration options are valid together.
    • Create any shared resources required by the rest of your plugin. For example, create clients for any services your plugin accesses.

    To the extent possible, the resources provided by your plugin shouldn’t assume that any other plugins have been installed before this one.

    This method will be called automatically during genkit.Init() when the user passes the plugin into the WithPlugins() option.

A single plugin can activate many new things within Genkit. For example, the Vertex AI plugin activates several new models as well as an embedder. Here’s how to build some common plugin types.

Genkit model plugins add one or more generative AI models to the Genkit registry. A model represents any generative model that is capable of receiving a prompt as input and generating text, media, or data as output.

Generally, a model plugin will make one or more genkit.DefineModel() calls in its Init function—once for each model the plugin is providing an interface to.

A model definition consists of three components:

  1. Metadata declaring the model’s capabilities.
  2. A configuration type with any specific parameters supported by the model.
  3. A generation function that accepts an ai.ModelRequest and returns an ai.ModelResponse, presumably using an AI model to generate the latter.

At a high level, here’s what it looks like in code:

package myplugin
import (
"context"
"fmt"
"[github.com/firebase/genkit/go/ai](https://github.com/firebase/genkit/go/ai)"
"[github.com/firebase/genkit/go/genkit](https://github.com/firebase/genkit/go/genkit)"
)
const providerID = "myProvider" // Unique ID for your plugin provider
// MyModelConfig defines the configuration options for your model.
// Embed ai.GenerationCommonConfig for common options.
type MyModelConfig struct {
ai.GenerationCommonConfig
AnotherCustomOption string `json:"anotherCustomOption,omitempty"`
CustomOption int `json:"customOption,omitempty"`
}
// DefineModel registers your custom model with Genkit.
func DefineMyModel(g *genkit.Genkit) {
genkit.DefineModel(g, providerID, "my-model",
&ai.ModelInfo{
Label: "My Model", // User-friendly label
Supports: &ai.ModelSupports{
Multiturn: true, // Does the model support multi-turn chats?
SystemRole: true, // Does the model support system messages?
Media: false, // Can the model accept media input?
Tools: false, // Does the model support function calling (tools)?
},
Versions: []string{"my-model-001"}, // List supported versions/aliases
},
// The generation function
func(ctx context.Context, mr *ai.ModelRequest, cb ai.ModelStreamCallback) (*ai.ModelResponse, error) {
// Verify that the request includes a configuration that conforms to your schema.
var cfg MyModelConfig
if mr.Config != nil {
// Attempt to cast the config; handle potential type mismatch
if typedCfg, ok := mr.Config.(*MyModelConfig); ok {
cfg = *typedCfg
} else {
// Handle incorrect config type if necessary, or rely on default values
// For simplicity, this example proceeds with default cfg if cast fails
}
}
// Now 'cfg' holds the configuration, either from the request or default.
// Use your custom logic to convert Genkit's ai.ModelRequest into a form
// usable by the model's native API.
apiRequest, err := apiRequestFromGenkitRequest(mr, cfg) // Pass config too
if err != nil {
return nil, fmt.Errorf("failed to create API request: %w", err)
}
// Send the request to the model API, using your own code or the model
// API's client library.
apiResponse, err := callModelAPI(ctx, apiRequest) // Pass context if needed
if err != nil {
return nil, fmt.Errorf("model API call failed: %w", err)
}
// Use your custom logic to convert the model's response to Genkit's ai.ModelResponse.
response, err := genResponseFromAPIResponse(apiResponse)
if err != nil {
return nil, fmt.Errorf("failed to convert API response: %w", err)
}
return response, nil
},
)
}
// Placeholder for the function that converts Genkit request to your API's format
func apiRequestFromGenkitRequest(mr *ai.ModelRequest, cfg MyModelConfig) (interface{}, error) {
// Implementation depends on your specific model API
fmt.Printf("Converting Genkit request with config: %+v\n", cfg)
// ... conversion logic ...
return "your-api-request-format", nil // Replace with actual request object
}
// Placeholder for the function that calls your model's API
func callModelAPI(ctx context.Context, apiRequest interface{}) (interface{}, error) {
// Implementation depends on your specific model API client library
// ... API call logic ...
return "your-api-response-format", nil // Replace with actual response object
}
// Placeholder for the function that converts your API's response to Genkit's format
func genResponseFromAPIResponse(apiResponse interface{}) (*ai.ModelResponse, error) {
// Implementation depends on your specific model API response format
// ... conversion logic ...
return &ai.ModelResponse{
Candidates: []*ai.Candidate{
{
Message: &ai.Message{
Content: []*ai.Part{ai.NewTextPart("Generated response text")},
Role: ai.RoleModel,
},
FinishReason: ai.FinishReasonStop,
},
},
}, nil // Replace with actual response conversion
}
// Example Plugin implementation
type MyPlugin struct{}
func (p *MyPlugin) Name() string {
return providerID
}
func (p *MyPlugin) Init(ctx context.Context, g *genkit.Genkit) error {
DefineMyModel(g)
// Define other models or resources here
return nil
}
// Ensure MyPlugin implements genkit.Plugin
var _ genkit.Plugin = &MyPlugin{}

Every model definition must contain, as part of its metadata, an ai.ModelInfo value that declares which features the model supports. Genkit uses this information to determine certain behaviors, such as verifying whether certain inputs are valid for the model. For example, if the model doesn’t support multi-turn interactions, then it’s an error to pass it a message history.

Note that these declarations refer to the capabilities of the model as provided by your plugin, and do not necessarily map one-to-one to the capabilities of the underlying model and model API. For example, even if the model API doesn’t provide a specific way to define system messages, your plugin might still declare support for the system role, and implement it as special logic that inserts system messages into the user prompt.

To specify the generation options a model supports, define and export a configuration type. Genkit has an ai.GenerationCommonConfig type that contains options frequently supported by generative AI model services, which you can embed or use outright.

Your generation function should verify that the request contains the correct options type.

The generation function carries out the primary work of a Genkit model plugin: transforming the ai.ModelRequest from Genkit’s common format into a format that is supported by your model’s API, and then transforming the response from your model into the ai.ModelResponse format used by Genkit.

Sometimes, this may require massaging or manipulating data to work around model limitations. For example, if your model does not natively support a system message, you may need to transform a prompt’s system message into a user-model message pair.

In addition to the resources that all plugins must export, a model plugin should also export the following:

  • A generation config type, as discussed earlier.

  • A Model() function, which returns references to your plugin’s defined models. Often, this can be:

    func Model(g *genkit.Genkit, name string) *ai.Model {
    return genkit.LookupModel(g, providerID, name)
    }
  • A ModelRef function, which creates a model reference paired with its config that can validate the type and be passed around together:

    func ModelRef(name string, config *MyModelConfig) *ai.ModelRef {
    return ai.NewModelRef(name, config)
    }
  • Optional: A DefineModel() function, which lets users define models that your plugin can provide, but that you do not automatically define. There are two main reasons why you might want to provide such a function:

    • Your plugin provides access to too many models to practically register each one. For example, the Ollama plugin can provide access to dozens of different models, with more added frequently. For this reason, it doesn’t automatically define any models, and instead requires the user to call DefineModel() for each model they want to use.

    • To give your users the ability to use newly-released models that you have not yet added to your plugin.

    A plugin’s DefineModel() function is typically a frontend to genkit.DefineModel() that defines a generation function, but lets the user specify the model name and model capabilities.

The Genkit libraries are instrumented with OpenTelemetry to support collecting traces, metrics, and logs. Genkit users can export this telemetry data to monitoring and visualization tools by installing a plugin that configures the OpenTelemetry Go SDK to export to a particular OpenTelemetry-capable system.

Genkit includes a plugin that configures OpenTelemetry to export data to Google Cloud Monitoring and Cloud Logging. To support other monitoring systems, you can extend Genkit by writing a telemetry plugin.

The primary job of a telemetry plugin is to configure OpenTelemetry to export data to a particular service. To do so, you need the following:

  • An implementation of OpenTelemetry’s SpanExporter interface that exports data to the service of your choice.
  • An implementation of OpenTelemetry’s metric.Exporter interface that exports data to the service of your choice.
  • Either a slog.Logger or an implementation of the slog.Handler interface, that exports logs to the service of your choice.

Depending on the service you’re interested in exporting to, this might be a relatively minor effort or a large one.

Because OpenTelemetry is an industry standard, many monitoring services already have libraries that implement these interfaces. For example, the googlecloud plugin for Genkit makes use of the opentelemetry-operations-go library, maintained by the Google Cloud team. Similarly, many monitoring services provide libraries that implement the standard slog interfaces.

On the other hand, if no such libraries are available for your service, implementing the necessary interfaces can be a substantial project.

Check the OpenTelemetry registry or the monitoring service’s docs to see if integrations are already available.

If you need to build these integrations yourself, take a look at the source of the official OpenTelemetry exporters and the page A Guide to Writing slog Handlers.

Every telemetry plugin needs to import the Genkit core library and several OpenTelemetry libraries:

// Import the Genkit core library.
"[github.com/firebase/genkit/go/genkit](https://github.com/firebase/genkit/go/genkit)"
// Import the OpenTelemetry libraries.
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/trace"

If you are building a plugin around an existing OpenTelemetry or slog integration, you will also need to import them.

A telemetry plugin should, at a minimum, support the following configuration options:

type Config struct {
// Export even in the dev environment.
ForceExport bool
// The interval for exporting metric data.
// The default is 60 seconds.
MetricInterval time.Duration
// The minimum level at which logs will be written.
// Defaults to [slog.LevelInfo].
LogLevel slog.Leveler
}

Most plugins will also include configuration settings for the service it’s exporting to (API key, project name, and so on).

The Init() function of a telemetry plugin should do all of the following:

  • Return early if Genkit is running in a development environment (such as when running with with genkit start) and the Config.ForceExport option isn’t set:

    shouldExport := cfg.ForceExport || os.Getenv("GENKIT_ENV") != "dev"
    if !shouldExport {
    return nil
    }
  • Initialize your trace span exporter and register it with Genkit:

    spanProcessor := trace.NewBatchSpanProcessor(YourCustomSpanExporter{})
    genkit.RegisterSpanProcessor(g, spanProcessor)
  • Initialize your metric exporter and register it with the OpenTelemetry library:

    r := metric.NewPeriodicReader(
    YourCustomMetricExporter{},
    metric.WithInterval(cfg.MetricInterval),
    )
    mp := metric.NewMeterProvider(metric.WithReader(r))
    otel.SetMeterProvider(mp)

    Use the user-configured collection interval (Config.MetricInterval) when initializing the PeriodicReader.

  • Register your slog handler as the default logger:

    logger := slog.New(YourCustomHandler{
    Options: &slog.HandlerOptions{Level: cfg.LogLevel},
    })
    slog.SetDefault(logger)

    You should configure your handler to honor the user-specified minimum log level (Config.LogLevel).

Because most generative AI flows begin with user input of some kind, it’s a likely possibility that some flow traces contain personally-identifiable information (PII). To protect your users’ information, you should redact PII from traces before you export them.

If you are building your own span exporter, you can build this functionality into it.

If you’re building your plugin around an existing OpenTelemetry integration, you can wrap the provided span exporter with a custom exporter that carries out this task. For example, the googlecloud plugin removes the genkit:input and genkit:output attributes from every span before exporting them using a wrapper similar to the following:

type redactingSpanExporter struct {
trace.SpanExporter
}
func (e *redactingSpanExporter) ExportSpans(ctx context.Context, spanData []trace.ReadOnlySpan) error {
var redacted []trace.ReadOnlySpan
for _, s := range spanData {
redacted = append(redacted, redactedSpan{s})
}
return e.SpanExporter.ExportSpans(ctx, redacted)
}
func (e *redactingSpanExporter) Shutdown(ctx context.Context) error {
return e.SpanExporter.Shutdown(ctx)
}
type redactedSpan struct {
trace.ReadOnlySpan
}
func (s redactedSpan) Attributes() []attribute.KeyValue {
// Omit input and output, which may contain PII.
var ts []attribute.KeyValue
for _, a := range s.ReadOnlySpan.Attributes() {
if a.Key == "genkit:input" || a.Key == "genkit:output" {
continue
}
ts = append(ts, a)
}
return ts
}

If you’re having trouble getting data to show up where you expect, OpenTelemetry provides a useful diagnostic tool that helps locate the source of the problem.

Genkit plugins can be published as normal Go packages. To increase discoverability, your package should have genkit somewhere in its name so it can be found with a simple search on pkg.go.dev. Any of the following are good choices:

  • github.com/yourorg/genkit-plugins/servicename
  • github.com/yourorg/your-repo/genkit/servicename

Genkit’s capabilities are designed to be extended by plugins. Genkit plugins are configurable modules that can provide models, retrievers, indexers, trace stores, and more. You’ve already seen plugins in action just by using Genkit:

import { genkit } from 'genkit';
import { vertexAI } from '@genkit-ai/vertexai';
const ai = genkit({
plugins: [vertexAI({ projectId: 'my-project' })],
});

The Vertex AI plugin takes configuration (such as the user’s Google Cloud project ID) and registers a variety of new models, embedders, and more with the Genkit registry. The registry powers Genkit’s local UI for running and inspecting models, prompts, and more as well as serves as a lookup service for named actions at runtime.

To create a plugin you’ll generally want to create a new NPM package:

Terminal window
mkdir genkitx-my-plugin
cd genkitx-my-plugin
npm init -y
npm install genkit
npm install --save-dev typescript
npx tsc --init

Then, define and export your plugin from your main entry point using the genkitPlugin helper:

import { Genkit, z, modelActionMetadata } from 'genkit';
import { GenkitPlugin, genkitPlugin } from 'genkit/plugin';
import { ActionMetadata, ActionType } from 'genkit/registry';
interface MyPluginOptions {
// add any plugin configuration here
}
export function myPlugin(options?: MyPluginOptions): GenkitPlugin {
return genkitPlugin(
'myPlugin',
// Initializer function (required): Registers actions defined upfront.
async (ai: Genkit) => {
// Example: Define a model that's always available
ai.defineModel({ name: 'myPlugin/always-available-model', ... });
ai.defineEmbedder(/* ... */);
// ... other upfront definitions
},
// Dynamic Action Resolver (optional): Defines actions on-demand.
async (ai: Genkit, actionType: ActionType, actionName: string) => {
// Called when an action (e.g., 'myPlugin/some-dynamic-model') is
// requested but not found in the registry.
if (actionType === 'model' && actionName === 'some-dynamic-model') {
ai.defineModel({ name: `myPlugin/${actionName}`, ... });
}
// ... handle other dynamic actions
},
// List Actions function (optional): Lists all potential actions.
async (): Promise<ActionMetadata[]> => {
// Returns metadata for all actions the plugin *could* provide,
// even if not yet defined dynamically. Used by Dev UI, etc.
// Example: Fetch available models from an API
const availableModels = await fetchMyModelsFromApi();
return availableModels.map(model => modelActionMetadata({
type: 'model',
name: `myPlugin/${model.id}`,
// ... other metadata
}));
}
);
}

The genkitPlugin function accepts up to three arguments:

  1. Plugin Name (string, required): A unique identifier for your plugin (e.g., 'myPlugin').
  2. Initializer Function (async (ai: Genkit) => void, required): This function runs when Genkit starts. Use it to register actions (models, embedders, etc.) that should always be available using ai.defineModel(), ai.defineEmbedder(), etc.
  3. Dynamic Action Resolver (async (ai: Genkit, actionType: ActionType, actionName: string) => void, optional): This function is called when Genkit tries to access an action (by type and name) that hasn’t been registered yet. It lets you define actions dynamically, just-in-time. For example, if a user requests model: 'myPlugin/some-model', and it wasn’t defined in the initializer, this function runs, giving you a chance to define it using ai.defineModel(). This is useful when a plugin supports many possible actions (like numerous models) and you don’t want to register them all at startup.
  4. List Actions Function (async () => Promise<ActionMetadata[]>, optional): This function should return metadata for all actions your plugin can potentially provide, including those that would be dynamically defined. This is primarily used by development tools like the Genkit Developer UI to populate lists of available models, embedders, etc., allowing users to discover and select them even if they haven’t been explicitly defined yet. This function is generally not called during normal flow execution.

In general, your plugin should take a single options argument that includes any plugin-wide configuration necessary to function. For any plugin option that requires a secret value, such as API keys, you should offer both an option and a default environment variable to configure it:

import { GenkitError, Genkit, z } from 'genkit';
import { GenkitPlugin, genkitPlugin } from 'genkit/plugin';
interface MyPluginOptions {
apiKey?: string;
}
export function myPlugin(options?: MyPluginOptions) {
return genkitPlugin('myPlugin', async (ai: Genkit) => {
if (!apiKey)
throw new GenkitError({
source: 'my-plugin',
status: 'INVALID_ARGUMENT',
message:
'Must supply either `options.apiKey` or set `MY_PLUGIN_API_KEY` environment variable.',
});
ai.defineModel(...);
ai.defineEmbedder(...)
// ....
});
};

A single plugin can activate many new things within Genkit. For example, the Vertex AI plugin activates several new models as well as an embedder.

Genkit model plugins add one or more generative AI models to the Genkit registry. A model represents any generative model that is capable of receiving a prompt as input and generating text, media, or data as output. Generally, a model plugin will make one or more defineModel calls in its initialization function.

A custom model generally consists of three components:

  1. Metadata defining the model’s capabilities.
  2. A configuration schema with any specific parameters supported by the model.
  3. A function that implements the model accepting GenerateRequest and returning GenerateResponse.

To build a model plugin, you’ll need to use the genkit/model package:

At a high level, a model plugin might look something like this:

import { genkitPlugin, GenkitPlugin } from 'genkit/plugin';
import { GenerationCommonConfigSchema } from 'genkit/model';
import { simulateSystemPrompt } from 'genkit/model/middleware';
import { Genkit, GenkitError, z } from 'genkit';
export interface MyPluginOptions {
// ...
}
export function myPlugin(options?: MyPluginOptions): GenkitPlugin {
return genkitPlugin('my-plugin', async (ai: Genkit) => {
ai.defineModel({
// be sure to include your plugin as a provider prefix
name: 'my-plugin/my-model',
// label for your model as shown in Genkit Developer UI
label: 'My Awesome Model',
// optional list of supported versions of your model
versions: ['my-model-001', 'my-model-001'],
// model support attributes
supports: {
multiturn: true, // true if your model supports conversations
media: true, // true if your model supports multimodal input
tools: true, // true if your model supports tool/function calling
systemRole: true, // true if your model supports the system role
output: ['text', 'media', 'json'], // types of output your model supports
},
// Zod schema for your model's custom configuration
configSchema: GenerationCommonConfigSchema.extend({
safetySettings: z.object({...}),
}),
// list of middleware for your model to use
use: [simulateSystemPrompt()]
}, async request => {
const myModelRequest = toMyModelRequest(request);
const myModelResponse = await myModelApi(myModelRequest);
return toGenerateResponse(myModelResponse);
});
});
};

The primary work of a Genkit model plugin is transforming the GenerateRequest from Genkit’s common format into a format that is recognized and supported by your model’s API, and then transforming the response from your model into the GenerateResponseData format used by Genkit.

Sometimes, this may require massaging or manipulating data to work around model limitations. For example, if your model does not natively support a system message, you may need to transform a prompt’s system message into a user/model message pair.

Action References (Models, Embedders, etc.)

Section titled “Action References (Models, Embedders, etc.)”

While actions like models and embedders can always be referenced by their string name (e.g., 'myPlugin/my-model') after being defined (either upfront or dynamically), providing strongly-typed references offers better developer experience through improved type checking and IDE autocompletion.

The recommended pattern is to attach helper methods directly to your exported plugin function. These methods use reference builders like modelRef and embedderRef from Genkit core.

First, define the type for your plugin function including the helper methods:

import { GenkitPlugin } from 'genkit/plugin';
import { ModelReference, EmbedderReference, modelRef, embedderRef, z } from 'genkit';
// Define your model's specific config schema if it has one
const MyModelConfigSchema = z.object({
customParam: z.string().optional(),
});
// Define the type for your plugin function
export type MyPlugin = {
// The main plugin function signature
(options?: MyPluginOptions): GenkitPlugin;
// Helper method for creating model references
model(
name: string, // e.g., 'some-model-name'
config?: z.infer<typeof MyModelConfigSchema>,
): ModelReference<typeof MyModelConfigSchema>;
// Helper method for creating embedder references
embedder(
name: string, // e.g., 'my-embedder'
config?: Record<string, any>, // Or a specific config schema
): EmbedderReference;
// ... add helpers for other action types if needed
};

Then, implement the plugin function and attach the helper methods before exporting:

// (Previous imports and MyPluginOptions interface definition)
import { modelRef, embedderRef } from 'genkit/model'; // Ensure modelRef/embedderRef are imported
function myPluginFn(options?: MyPluginOptions): GenkitPlugin {
return genkitPlugin(
'myPlugin',
async (ai: Genkit) => {
// Initializer...
},
async (ai, actionType, actionName) => {
// Dynamic resolver...
// Example: Define model if requested dynamically
if (actionType === 'model') {
ai.defineModel(
{
name: `myPlugin/${actionName}`,
// ... other model definition properties
configSchema: MyModelConfigSchema, // Use the defined schema
},
async (request) => {
/* ... model implementation ... */
},
);
}
// Handle other dynamic actions...
},
async () => {
// List actions...
},
);
}
// Create the final export conforming to the MyPlugin type
export const myPlugin = myPluginFn as MyPlugin;
// Implement the helper methods
myPlugin.model = (
name: string,
config?: z.infer<typeof MyModelConfigSchema>,
): ModelReference<typeof MyModelConfigSchema> => {
return modelRef({
name: `myPlugin/${name}`, // Automatically prefixes the name
configSchema: MyModelConfigSchema,
config,
});
};
myPlugin.embedder = (name: string, config?: Record<string, any>): EmbedderReference => {
return embedderRef({
name: `myPlugin/${name}`,
config,
});
};

Now, users can import your plugin and use the helper methods for type-safe action references:

import { genkit } from 'genkit';
import { myPlugin } from 'genkitx-my-plugin'; // Assuming your package name
const ai = genkit({
plugins: [
myPlugin({
/* options */
}),
],
});
async function run() {
const { text } = await ai.generate({
// Use the helper for a type-safe model reference
model: myPlugin.model('some-model-name', { customParam: 'value' }),
prompt: 'Tell me a story.',
});
console.log(text);
const embeddings = await ai.embed({
// Use the helper for a type-safe embedder reference
embedder: myPlugin.embedder('my-embedder'),
content: 'Embed this text.',
});
console.log(embeddings);
}
run();

This approach keeps the plugin definition clean while providing a convenient and type-safe way for users to reference the actions provided by your plugin. It works seamlessly with both statically and dynamically defined actions, as the references only contain metadata, not the implementation itself.

Genkit plugins can be published as normal NPM packages. To increase discoverability and maximize consistency, your package should be named genkitx-{name} to indicate it is a Genkit plugin and you should include as many of the following keywords in your package.json as are relevant to your plugin:

  • genkit-plugin: always include this keyword in your package to indicate it is a Genkit plugin.
  • genkit-model: include this keyword if your package defines any models.
  • genkit-retriever: include this keyword if your package defines any retrievers.
  • genkit-indexer: include this keyword if your package defines any indexers.
  • genkit-embedder: include this keyword if your package defines any indexers.
  • genkit-telemetry: include this keyword if your package defines a telemetry provider.
  • genkit-deploy: include this keyword if your package includes helpers to deploy Genkit apps to cloud providers.
  • genkit-flow: include this keyword if your package enhances Genkit flows.

A plugin that provided a retriever, embedder, and model might have a package.json that looks like:

{
"name": "genkitx-my-plugin",
"keywords": ["genkit-plugin", "genkit-retriever", "genkit-embedder", "genkit-model"],
// ... dependencies etc.
}