Genkit Middleware: Intercept, extend, and harden your agentic apps Blog

shallow-mind1 pts0 comments

Announcing Genkit Middleware: Intercept, extend, and harden your agentic apps

- Google Developers Blog

Search

Announcing Genkit Middleware: Intercept, extend, and harden your agentic apps

MAY 14, 2026

Chris Gill

Product Manager

Share

Facebook

Twitter

LinkedIn

Mail

Genkit is an open-source framework for building full-stack, AI-powered and agentic applications for any platform with support for TypeScript, Go, Dart, and Python. Building a production-ready agentic applications and AI features requires more than powerful models and careful prompting. You might need retries and fallbacks for maximum reliability, human approval before destructive tool calls, and observability across every layer.<br>Genkit solves this with middleware : composable hooks that intercept generation calls, including the tool execution loop, and inject custom behaviors. The middleware system is available today in TypeScript, Go, and Dart, with Python support coming soon.<br>How Genkit middleware works<br>Every generate() call in Genkit runs a tool loop : the model produces output, any requested tools execute, the results feed back into a new model call, and the cycle repeats until the model is done. Middleware hooks attach at three layers of this loop:

Hook

When it runs

Typical use

Generate

Once per tool-loop iteration

Context injection, message rewriting, conversation-level logic

Model

Once per model API call

Retry, fallback, caching, latency logging

Tool

Once per tool execution

Human-in-the-loop, sandboxing, per-tool logging

Pre-built middleware<br>Genkit offers several pre-built middleware solutions for common use-cases. Here's what's available today:<br>1. Retry<br>Automatically retries failed model API calls on transient errors (RESOURCE_EXHAUSTED, UNAVAILABLE, etc.) using exponential backoff with jitter. Only the model call is retried; the surrounding tool loop is not replayed.

resp, err := genkit.Generate(ctx, g,<br>ai.WithModelName("googleai/gemini-flash-latest"),<br>ai.WithPrompt("Summarize the quarterly earnings report."),<br>ai.WithUse(&middleware.Retry{<br>MaxRetries: 3,<br>InitialDelayMs: 1000,<br>BackoffFactor: 2,<br>}),

Go

Copied

2. Fallback<br>Switches to an alternative model when the primary model fails on a specified set of error codes. Useful for falling back to a completely different provider when your primary model exceeds its quota.

resp, err := genkit.Generate(ctx, g,<br>ai.WithModelName("googleai/gemini-flash-latest"),<br>ai.WithPrompt("Analyze this complex document..."),<br>ai.WithUse(&middleware.Fallback{<br>Models: []ai.ModelRef{<br>anthropic.ModelRef("claude-sonnet-4-6", nil), // fall back to Claude<br>},<br>Statuses: []core.StatusName{core.RESOURCE_EXHAUSTED},<br>}),

Go

Copied

3. Tool approval<br>Restricts tool execution to an allow-list. Any tool not on the list triggers an interrupt, enabling human-in-the-loop confirmation before the action proceeds.

resp, _ := genkit.Generate(ctx, g,<br>ai.WithPrompt("Delete the temp files"),<br>ai.WithTools(deleteFilesTool),<br>ai.WithUse(&middleware.ToolApproval{<br>AllowedTools: []string{}, // empty = every tool call interrupts<br>}),

if len(resp.Interrupts()) > 0 {<br>interrupt := resp.Interrupts()[0]

// Prompt the user for approval, then resume with the approval flag.<br>approved, _ := deleteFilesTool.RestartWith(interrupt,<br>ai.WithResumedMetadata[DeleteInput](map[string]any{"toolApproved": true}),

resp, err := genkit.Generate(ctx, g,<br>ai.WithMessages(resp.History()...),<br>ai.WithTools(deleteFilesTool),<br>ai.WithToolRestarts(approved),<br>ai.WithUse(&middleware.ToolApproval{}),<br>fmt.Println(resp.Text())

Go

Copied

4. Skills<br>Scans a directory for SKILL.md files and injects their content into the system prompt. Also exposes a use_skill tool so the model can load specific skills on demand.

resp, err := genkit.Generate(ctx, g,<br>ai.WithPrompt("How do I deploy this service?"),<br>ai.WithUse(&middleware.Skills{SkillPaths: []string{"./skills"}}),

Go

Copied

5. Filesystem<br>Gives the model scoped access to the local filesystem through injected tools (list_files, read_file, plus write_file and edit_file when writes are enabled). Path safety is enforced so the model can never escape the root directory.

resp, err := genkit.Generate(ctx, g,<br>ai.WithPrompt("Create a hello world program in the workspace"),<br>ai.WithUse(&middleware.Filesystem{<br>RootDir: "./workspace",<br>AllowWriteAccess: true,<br>}),

Go

Copied

Building custom middleware<br>The pre-built middleware covers common scenarios, but the real power of the system is in writing your own. Imagine you're building an agentic customer-support app and need to ensure the model never mentions competitor products or internal pricing data. Rather than encoding these rules in every prompt, you can enforce them deterministically with middleware.<br>Custom middleware follows a simple contract across all languages: provide a name and a factory function that returns the hooks you want. The factory is called once per generate() invocation, and you implement only the hooks you need.<br>Here's a complete, custom...

middleware genkit model tool resp generate

Related Articles