The Flutter Kit logoThe Flutter Kit
Tutorial

Flutter GenUI SDK Tutorial: AI-Generated UIs with Gemini (2026)

Complete tutorial for Flutter GenUI: widget catalog, structured output, tool calls, and a working shopping-assistant example.

Ahmed GaganAhmed Gagan
17 min read

Flutter GenUI SDK shipped in alpha earlier this year and it changes how AI features look in mobile apps. Instead of a chat bubble with plain text, the model returns a typed widget tree that your app renders directly. Think of it as function-calling where the function is "build me a UI that answers the user's question." This guide walks through the entire pipeline, from setting up Firebase AI Logic with Gemini, to defining your widget catalog, to shipping a production shopping assistant.

Short version: GenUI works by giving Gemini a catalog of named Flutter widgets with typed parameters. The model responds with a JSON tree that names which widgets to render and what data to feed them. Your app parses the tree against the catalog and builds a real Flutter UI. It feels like magic the first time it works.

What GenUI actually is (versus regular AI chat)

Regular AI chat in Flutter is a text stream in, text stream out. The user asks a question, the model writes Markdown, your app renders the Markdown. Works fine for general-purpose chat.

GenUI is different. The user asks a question, the model responds with a structured UI specification, and your app renders real Flutter widgets from that specification. The difference in feel is night and day: a user asking "what should I wear tomorrow" gets a weather card plus an outfit grid, not a paragraph of text. A user asking "compare these two headphones" gets a side-by-side spec table, not a list of bullet points.

The 2026 Flutter GenUI SDK lives at package:flutter_genui and ships three pieces.

  • Widget catalog. You declare which widgets the model is allowed to produce. The catalog is a list of CatalogItem entries with typed parameter schemas.
  • GenUI manager. The runtime that takes a user message, packages the catalog as a structured output schema, sends it to Gemini, receives a tree, and turns that tree back into Flutter widgets.
  • Tool system. Models can call functions you expose to fetch data (the weather, a product list, a user profile) before building the UI. Gemini supports this natively.

Setup: Firebase AI Logic plus the SDK

You need two packages. flutter_genui for the GenUI runtime andfirebase_ai for the Gemini bridge. Firebase AI Logic is preferred over raw Google Generative AI because App Check handles client-side abuse protection out of the box.

# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_genui: ^1.0.0
  firebase_ai: ^2.4.0
  firebase_core: ^3.8.0
  firebase_app_check: ^0.3.2

Initialize Firebase and App Check in main.dart. Use Play Integrity on Android and DeviceCheck on iOS. Debug provider for local testing.

Defining the widget catalog

The catalog is the single most important piece of your GenUI app. A well-designed catalog gives the model enough vocabulary to express intent but not so much that it hallucinates unsupported widgets. Start with 5 to 8 widget types.

WidgetPurposeParameters
ProductCardSingle product summary with image, title, price, CTAimageUrl, title, price, currency, onTap
ProductGridGrid of up to 6 ProductCarditems (list), columns
ComparisonTableSide-by-side spec table for 2-3 itemsitems (list), attributes (list)
InfoCardHeadline plus body text plus optional icontitle, body, icon, color
ActionButtonPrimary action with callbacklabel, style, action
FactListNumbered or bulleted list of structured factsitems (list), ordered

The trick is that every parameter is typed and every catalog item has a description explainingwhen to use it. Gemini reads the descriptions and uses them to pick widgets. Think of the catalog like a typed API for the model.

final catalog = WidgetCatalog(items: [
  CatalogItem(
    name: 'ProductCard',
    description: 'Show a single product with image, title, and price.',
    parameters: Schema.object(properties: {
      'imageUrl': Schema.string(description: 'Product image URL'),
      'title':    Schema.string(),
      'price':    Schema.number(),
      'currency': Schema.string(description: 'ISO 4217 like USD, EUR'),
    }),
    builder: (params) => ProductCard(
      imageUrl: params['imageUrl'],
      title:    params['title'],
      price:    params['price'],
      currency: params['currency'],
    ),
  ),
  // ... other items
]);

Writing a structured-schema prompt

GenUI prompts have three layers: the system instructions (who the model is), the tool definitions (what it can call), and the response schema (how it must structure its answer). The SDK builds the schema for you from the catalog, but you still write the system instructions.

The golden rules for GenUI system prompts:

  • Tell the model which widget to use for which intent. "If the user asks to compare items, use ComparisonTable. If they ask to browse, use ProductGrid."
  • Give it a rule for short responses. "For quick facts use InfoCard. Never respond with raw text; always return a widget tree."
  • Bound the parameters. "Never return a ProductGrid with more than 6 items. Paginate by suggesting an ActionButton with label Load More."
  • Forbid hallucination. "Never invent product data. Always call searchProducts() first."

Tool-calling for interactive UIs

The second reason GenUI is more powerful than chat is tool use. Before generating the UI, Gemini can call a Dart function you expose, wait for the result, and use the returned data to populate the widget tree. This is how "compare these two headphones" actually pulls real product data instead of making it up.

final tools = [
  Tool(
    name: 'searchProducts',
    description: 'Search the catalog by query and return up to 6 items.',
    parameters: Schema.object(properties: {
      'query':    Schema.string(),
      'category': Schema.string(enumValues: ['headphones', 'laptops', 'phones']),
    }),
    execute: (args) async {
      final results = await productRepo.search(args['query'], args['category']);
      return results.map((p) => p.toJson()).toList();
    },
  ),
];

The SDK handles the tool-call protocol automatically. Gemini decides when to call the tool, waits for the response, and incorporates the data before producing the final widget tree. Your app only sees the final result.

Production gotchas that will bite you

Shipping GenUI to production is different from the demo. A few things to watch:

  • Safety filters block rendering. Gemini's safety classifiers sometimes return an empty response on edge-case queries. Always have a fallback: if the response is null or fails schema validation, render an InfoCard with a friendly message and anActionButton to retry.
  • Streaming feels weird. Unlike chat, streaming partial widgets is not useful. Show a skeleton shimmer while the response builds and render all at once.
  • Token cost is higher than chat. Structured output inflates token usage by 2 to 3x. Budget accordingly.
  • Latency is real. Expect 1.2 to 2.5 seconds per turn on Gemini 2.5 Flash. If your app feels snappy today, GenUI will feel slow. Use Flash Lite for simple catalogs and reserve Pro for compare-and-reason turns.
  • Catalog drift is deadly. Every time you add a widget, update the prompt. If you remove a widget, invalidate any cached catalog the model might be using. GenUI assumes a fixed catalog per app version.
  • Accessibility is your job. The model does not know your widgets needSemantics labels. Bake accessibility into the catalog builders.

GenUI versus AI Toolkit versus raw Gemini SDK

ToolBest forLimitation
Flutter GenUI SDKDynamic UI generation, shopping assistants, comparison toolsCatalog setup takes a day; not meant for simple chat
Flutter AI ToolkitChatGPT-style conversations with multi-provider supportPlain text only, not structured UI
Raw Gemini SDKCustom flows, one-off integrations, full controlYou build everything from scratch

Pick GenUI when the answer benefits from structure (comparisons, lists of products, data tables, form-like interactions). Pick AI Toolkit when the answer is prose (drafting, explaining, summarizing). Pick the raw SDK only when neither fits.

A working shopping-assistant example

Here is the minimum viable GenUI shopping assistant. User types "find me wireless headphones under $200." Gemini calls searchProducts, gets 6 results, and returns aProductGrid. The user taps a card and Gemini responds with aComparisonTable plus an ActionButton to buy.

final genUI = GenUiManager(
  model: FirebaseAI.vertexAI().generativeModel(model: 'gemini-2.5-flash'),
  catalog: catalog,
  tools: tools,
  systemPrompt: '''
You are a shopping assistant. Every response must be a widget tree from the catalog.
- Browsing queries return ProductGrid (max 6 items).
- Comparison queries return ComparisonTable.
- Quick facts return InfoCard.
- Always call searchProducts before returning product data.
''',
);

// In your StatefulWidget
Future<void> onUserMessage(String text) async {
  setState(() => _loading = true);
  final result = await genUI.generate(text);
  setState(() {
    _widget = result.widget; // typed Flutter widget
    _loading = false;
  });
}

Roughly 60 lines of Dart between the catalog, the tool, and the UI. The rest is the model.

Shipping it in a real app

A production checklist for your first GenUI feature:

  • Catalog locked for the app version, documented in version control
  • System prompt committed alongside the catalog
  • Tool functions return typed JSON, not Dart objects
  • App Check enabled for both iOS and Android in production
  • Fallback UI for empty responses and schema failures
  • Skeleton shimmer while generating
  • Analytics event on every successful generation (measure latency, tokens, cost)
  • Rate limit on the server side (Firebase Cloud Function) to prevent abuse even with App Check
  • Subscription gate for expensive catalogs (10+ widgets or 1M+ token system prompts)

What The Flutter Kit gives you

The Flutter Kit ships a working GenUI shopping-assistant template with a 12-widget catalog, 4 example tools, App Check pre-configured, a subscription gate via RevenueCat on the premium tier, and analytics events wired to PostHog. Swap the product data source for your own API and you have a shippable AI feature in an afternoon.

$69 one-time, unlimited commercial projects. See every integration on the features page or jump to checkout.

Final recommendation

GenUI is not a replacement for chat; it is a replacement for forms, dashboards, and search results. If your app has a feature where the user asks a question and the best answer is a structured card or table, you should be using GenUI instead of text chat. Start with a five-item catalog, ship it, then grow. Every indie Flutter app that ships a GenUI feature in 2026 will stand out from the 2025 chat-bubble cohort.

Share this article

Ready to ship your Flutter app faster?

The Flutter Kit gives you a production-ready Flutter codebase with onboarding, paywalls, auth, AI integrations, and more. Stop building boilerplate. Start building your product.

Get The Flutter Kit