Skip to content

Server integration

Pick the server framework that matches your backend. Each guide is self-contained and shows how to expose a Genkit flow as an HTTP endpoint that any client, web, mobile, or another service, can call.

Every guide above mounts a flow with the same two functions:

func Handler(a api.Action, opts ...HandlerOption) http.HandlerFunc
func HandlerFunc(a api.Action, opts ...HandlerOption) func(http.ResponseWriter, *http.Request) error

Handler returns an http.HandlerFunc, so it satisfies http.Handler and can be wrapped by any standard middleware. HandlerFunc returns an error instead of writing it, which suits frameworks with centralized error middleware.

The argument is any api.Action: a flow from genkit.DefineFlow or genkit.DefineStreamingFlow, or an *aix.Agent, which implements api.BidiAction and is served one turn per request.

What the handler does on the wire:

ConcernBehavior
Request body{"data": <flow input>}. The input is validated against the flow’s schema.
Non-streaming responseapplication/json body of {"result": <flow output>}.
Streaming responsetext/event-stream when the request sends Accept: text/event-stream or ?stream=true. Each event is data: {"message": <chunk>}, then a final data: {"result": <output>}.
OptionsVariadic HandlerOption. Today: genkit.WithContextProviders (see Passing information through context) and genkit.WithStreamManager (see Durable streaming). An option that fails to apply panics at construction, not per request, so a misconfiguration fails at startup.
ContextThe action runs with the request’s own r.Context(), so values attached by HTTP middleware reach the flow, its tools, and its prompts. A client disconnect cancels that context and therefore the in-flight model call. The one exception is a durable stream, which deliberately keeps running after the client goes away.

The handler derives the HTTP status from the error the flow returns, using the same classification described in Error types:

  • status.Of(err).HTTPCode() picks the status. An unclassified error, such as a bare errors.New, is Internal and becomes a 500.
  • The error’s message is withheld from the client unless you built it with status.PublicErrorf. Everything else is replaced with a generic string derived from the status. The full error is always logged server-side.
  • On a streaming request the response has already committed a 200, so a mid-stream failure arrives as a terminal data: {"error": {"status": ..., "message": ...}} event instead of a status code. See Errors on a streaming request.

Two deployment settings can truncate a stream that the code handles correctly:

  • An http.Server with a WriteTimeout cuts the response off at that deadline. Leave it unset, or set it longer than your slowest generation, for routes that stream.
  • A reverse proxy that buffers responses holds every event until the flow finishes. Disable response buffering on the streaming route.

Once your backend exposes flows as HTTP endpoints, connect a frontend:

  • Web client — call flows from any JavaScript/TypeScript web app
  • Flutter — call flows from a Flutter mobile, desktop, or web app
  • Or use any of the app integration guides, full-stack frameworks like Next.js, SvelteKit, Nuxt, and others can also consume a standalone Genkit backend