top of page

Code-Along With Genkit Middleware: Retries, Fallbacks, Approval Gates, and Skills for Production Agents

  • Jun 29
  • 2 min read

On May 14, 2026, Google announced Genkit Middleware, a composable hook system for the open-source Genkit framework that intercepts generation calls and the tool execution loop. The release lands four prebuilt middleware components plus a Skills system. TypeScript, Go, and Dart are supported at launch, with Python on the way.

What ships in Genkit Middleware

  • Retry middleware: retries failed model API calls on transient errors such as RESOURCE_EXHAUSTED and UNAVAILABLE using exponential backoff with jitter. Only the model call is retried, the surrounding tool loop is not replayed.

  • Fallback middleware: switches to an alternative model when the primary fails on a specified set of error codes, including across providers.

  • Approval-gate middleware: pauses execution before sensitive tool calls and waits for an explicit signal, intended for write actions and anything that touches money or production state.

  • Filesystem-access middleware: scopes file reads and writes to specific directories so the agent cannot escape the sandbox.

  • Skills system: dynamically injects instructions from local Markdown files into a flow, so domain behavior can be added without code changes.

Install Genkit

npm install genkit @genkit-ai/googleai

Wrap a generate call with retry and fallback

The middleware shape from the announcement composes around any generate call. The retry middleware handles transient model failures, and the fallback middleware swaps to a second model when the primary returns an error on the configured codes.

import { genkit } from 'genkit';
import { googleAI, gemini } from '@genkit-ai/googleai';
import { retry, fallback } from 'genkit/middleware';

const ai = genkit({ plugins: [googleAI()] });

const result = await ai.generate({
  model: gemini('gemini-2.5-flash'),
  prompt: 'Summarize the changelog for our release',
  use: [
    retry({ maxAttempts: 3 }),
    fallback({
      model: gemini('gemini-2.5-pro'),
      onCodes: ['RESOURCE_EXHAUSTED', 'UNAVAILABLE'],
    }),
  ],
});

Gate a sensitive tool with approval

Approval gates apply to tools rather than the model call. The flow pauses on entry to the wrapped tool, surfaces the proposed arguments, and resumes only on an explicit approve signal. This is the canonical pattern for any tool that writes to production.

import { approvalGate } from 'genkit/middleware';

const transferFunds = ai.defineTool(
  { name: 'transferFunds', /* input schema */ },
  async (input) => { /* perform transfer */ },
);

const guardedTransfer = approvalGate(transferFunds, {
  prompt: (input) => `Approve transfer of $${input.amount} to ${input.account}?`,
});

Things to validate in production

  • Confirm fallback paths log a clear marker so a downstream monitor can distinguish primary versus fallback responses.

  • Tune retry maxAttempts and base delay against your actual quota windows, not a default that may stack against rate limits.

  • Pin Skills files to a known revision so a Markdown edit cannot silently change agent behavior in production.

Sources

 
 
bottom of page