Back to Blog

Building Real-Time UIs with the Gemini API

AIGeminiVue.js

One of the talks I've given most recently โ€” at Google Developer Groups in Lisbon and Lagos โ€” focused on a question that kept coming up in my own work: how do you build reliable, real-time user interfaces powered by LLM output?

The core challenge is simple to state but hard to solve: LLMs generate text. UIs need structure. How do you bridge that gap without your application breaking every time the model returns something unexpected?

The problem with unstructured output

If you've ever tried to parse free-form LLM text into a UI component, you know the pain. The model might return valid JSON one time and a conversational response the next. Or it might nest objects differently than expected. Or include markdown in a field you expected to be plain text.

For a demo, this is fine. For production, it's a dealbreaker.

Structured output to the rescue

The Gemini API's structured output feature changes this equation entirely. By defining a JSON schema in your API request, you get deterministic, parseable responses every time. The model is constrained to only produce output that matches your schema.

const schema = {
  type: "object",
  properties: {
    title: { type: "string" },
    items: {
      type: "array",
      items: {
        type: "object",
        properties: {
          name: { type: "string" },
          description: { type: "string" },
          priority: { type: "string", enum: ["high", "medium", "low"] }
        }
      }
    }
  }
}

With this schema, every response from Gemini will be valid, parseable JSON that your Vue.js component can render immediately โ€” no try/catch, no fallback UI, no "sorry, something went wrong."

Streaming makes it real-time

The second piece of the puzzle is streaming. Rather than waiting for the full response, you can stream structured output token by token and render partial results. This creates the feeling of a UI that's being "built" in real-time right in front of the user.

In Vue.js, this maps beautifully to reactive data. As each chunk arrives, you update a reactive ref, and Vue's reactivity system handles the rest.

Key takeaways

After shipping this pattern in production at Agosto, here's what I've learned:

  1. Always use structured output in production โ€” free-form text parsing is too fragile
  2. Stream everything โ€” users perceive streamed UIs as faster, even when total time is the same
  3. Design your schema around your UI components โ€” the closer the schema matches your component props, the less transformation code you need
  4. Handle partial state gracefully โ€” during streaming, your data is incomplete. Design components that look good at every stage of completion

The combination of Gemini's structured output and Vue.js reactivity creates a developer experience that's genuinely enjoyable. You define what you want, and the AI fills it in โ€” reliably, every time.