Shelf Integration
Shelf is a modular and flexible web server middleware ecosystem for Dart, perfect for building REST APIs with Genkit. The genkit_shelf package provides the shelfHandler function to easily expose individual Genkit flows as Shelf handlers.
Installation
Section titled “Installation”Add the genkit_shelf, shelf, and shelf_router packages to your project:
dart pub add genkit_shelf shelf shelf_routerBasic Setup (Manual Routing)
Section titled “Basic Setup (Manual Routing)”The primary way to use Genkit with Shelf is to mount flow handlers onto a shelf_router. This gives you full control over your server’s routing, middleware, and configuration.
import 'dart:io';import 'package:genkit/genkit.dart';import 'package:genkit_shelf/genkit_shelf.dart';import 'package:shelf/shelf.dart';import 'package:shelf/shelf_io.dart' as io;import 'package:shelf_router/shelf_router.dart';import 'package:schemantic/schemantic.dart';
// part 'server.g.dart';
void main() async { final ai = Genkit();
// 1. Define your flow final helloFlow = ai.defineFlow( name: 'hello', fn: (String name, _) async => 'Hello, $name!', inputSchema: .string(), outputSchema: .string(), );
// 2. Create a Shelf Router final router = Router();
// 3. Mount the flow handler at a specific path // 'shelfHandler' converts the Flow into a Shelf Handler router.post('/hello', shelfHandler(helloFlow));
// 4. Add other application routes router.get('/health', (_) => Response.ok('OK'));
// 5. Create a handler pipeline (e.g., adding logging) final handler = const Pipeline() .addMiddleware(logRequests()) .addHandler(router.call);
// 6. Start the server final server = await io.serve(handler, InternetAddress.anyIPv4, 8080); print('Server running on http://localhost:${server.port}');}Serving Models
Section titled “Serving Models”You can also serve AI models (and other Genkit actions) using startFlowServer or shelfHandler. This allows you to expose models as web endpoints that can be consumed by other Genkit applications using defineRemoteModel.
import 'dart:io';import 'package:genkit/genkit.dart';import 'package:genkit_google_genai/genkit_google_genai.dart';import 'package:genkit_shelf/genkit_shelf.dart';import 'package:shelf/shelf_io.dart' as io;import 'package:shelf_router/shelf_router.dart';
void main() async { // Initialize your model plugin final geminiApi = googleAI(); final geminiFlash = geminiApi.model('gemini-2.5-flash');
// Create a Shelf Router final router = Router();
// Serve the model using shelfHandler router.post('/googleai/gemini-2.5-flash', shelfHandler(geminiFlash));
final server = await io.serve(router.call, InternetAddress.anyIPv4, 8080); print('Server running on http://localhost:${server.port}');}Running Your Application
Section titled “Running Your Application”Run your server using the Dart CLI:
dart run bin/server.dartTesting Your Endpoints
Section titled “Testing Your Endpoints”You can test your endpoints using curl or any HTTP client.
Unary Request
Section titled “Unary Request”curl -X POST http://localhost:8080/hello \ -H "Content-Type: application/json" \ -d '{"data": "World"}'Streaming Request
Section titled “Streaming Request”If your flow supports streaming (defines a streamSchema), shelfHandler automatically handles streaming responses when requested.
curl -X POST "http://localhost:8080/count?stream=true" \ -H "Content-Type: application/json" \ -d '{"data": 5}'Advanced Features
Section titled “Advanced Features”Authentication and Context
Section titled “Authentication and Context”You can use standard Shelf middleware to handle authentication, or communicating with Genkit’s context system using FlowWithContextProvider.
Using Genkit Context Provider
Section titled “Using Genkit Context Provider”The shelfHandler function accepts an optional contextProvider argument. This function allows you to inspect the incoming Shelf Request and populate the Genkit flow context.
import 'package:shelf/shelf.dart';
// ...
final secureFlow = ai.defineFlow( name: 'secure', fn: (String input, ctx) async { final user = ctx.context?['user']; if (user == null) { throw GenkitException( 'Unauthorized access', status: StatusCodes.permissionDenied, ); } return 'Secure data for $user: $input'; }, inputSchema: .string(), outputSchema: .string(),);
// Directly pass the context provider to shelfHandlerfinal authenticatedHandler = shelfHandler( secureFlow, contextProvider: (Request request) { final authHeader = request.headers['Authorization']; if (authHeader == 'Bearer secret') { return {'user': 'Admin'}; } return {}; },);
router.post('/secure', authenticatedHandler);Using Shelf Middleware
Section titled “Using Shelf Middleware”You can also use standard Shelf middleware (like shelf_auth) to validate credentials before the request reaches the Genkit handler. However, if you need to pass user information into the flow (e.g., user ID), using contextProvider is the recommended bridge.
Alternative: Simplified Server
Section titled “Alternative: Simplified Server”For quick prototypes or simple services where you don’t need custom routing control, you can use startFlowServer. This helper function creates a Shelf server, sets up routing for all provided flows, and handles CORS automatically.
import 'package:genkit/genkit.dart';import 'package:genkit_shelf/genkit_shelf.dart';
void main() async { final ai = Genkit(); final myFlow = ai.defineFlow(...);
await startFlowServer( flows: [myFlow], port: 3400, cors: { 'origin': '*', }, );}Deployment
Section titled “Deployment”Since a Genkit Shelf application is just a standard Dart HTTP server, you can deploy it to any platform that supports Dart or Docker containers, such as Google Cloud Run.
-
Create a Dockerfile:
FROM dart:stable AS buildWORKDIR /appCOPY pubspec.* ./RUN dart pub getCOPY . .RUN dart compile exe bin/server.dart -o bin/serverFROM scratchCOPY --from=build /runtime/ /COPY --from=build /app/bin/server /app/bin/CMD ["/app/bin/server"] -
Build and Deploy (e.g., using Cloud Build and Cloud Run).