Beyond the Prompt: Engineering Generative UI Workflows with Expo and the Vercel AI SDK
Stop settling for chat bubbles and start streaming functional React Native components directly to your users. I break down how to leverage the Vercel AI SDK and Expo to build intent-driven interfaces that feel like magic.

Beyond the Prompt: Engineering Generative UI Workflows with Expo and the Vercel AI SDK
For the past few months, I’ve been obsessed with a single problem: The Chat Bubble Trap.
We’ve all seen it. You integrate an LLM into your mobile app, and suddenly everything looks like a Slack clone. But as software engineers, we know that text is a primitive. Users don't want to read a paragraph about their budget; they want to see a chart. They don't want to read instructions on how to book a flight; they want a booking widget pre-filled with their intent.
In my recent projects, I’ve been pushing the boundaries of what’s possible with Expo and the Vercel AI SDK, moving from Generative Text to Generative UI. Here is how I’m engineering these workflows to create truly intent-driven mobile experiences.
The Lightbulb Moment: UI as a Tool
The breakthrough came when I stopped thinking of the LLM as a message generator and started treating it as a state-machine orchestrator.
Using the Vercel AI SDK (specifically ai/rsc or the newer generateText tools pattern), we can define "tools" that aren't just for fetching data, but for signaling UI changes. In an Expo environment, this means the server streams back a signal that triggers a specific, high-fidelity React Native component on the client.
The Architecture
Here’s the stack that’s been winning for me:
- Expo (React Native): For the cross-platform runtime.
- Vercel AI SDK: To handle the streaming protocol and tool-calling logic.
- Next.js Route Handlers: Serving as our AI gateway.
1. Defining the Tool on the Backend
Instead of just returning text, I define a tool that the model can call when it detects a specific user intent (e.g., "show me my recent spending").
2. Consuming the Stream in Expo
On the mobile side, the useChat hook from @ai-sdk/react is surprisingly robust in an Expo environment. The key is how we handle the toolInvocations to render the right component.
The "Engineering" Part: Lessons from the Trenches
1. The Hydration Headache
In React Native, we don't have the luxury of some of the DOM-based streaming features. I found that managing the "loading" state of a tool call is critical. If the LLM decides to call a tool, there’s a gap between the tool call and the data returning. I now always implement a Skeleton state within the toolInvocation loop to ensure the UI doesn't jump.
2. Latency vs. Fidelity
Generating a massive JSON blob for a chart can be slow. I’ve started experimenting with multi-step generations. The first step generates the text acknowledgment ("Sure, let me pull that up...") and the second step (parallel or sequential) fetches the heavy UI data. This keeps the interface feeling snappy.
3. Shared Schemas
One of the biggest pain points was keeping the Zod schemas in the Next.js backend in sync with the TypeScript interfaces in the Expo app. I highly recommend a Monorepo (Turborepo) setup here. Sharing a types package between your Expo app and your AI gateway is the only way to maintain sanity as your UI library grows.
Why This Matters
We are moving toward an era of Just-in-Time UI. Instead of building 50 different screens for every possible edge case, we build a library of high-quality components and let the AI assemble the workflow based on the user's specific context.
When you combine Expo’s ability to deliver beautiful native experiences with the Vercel AI SDK’s streaming power, you aren't just building a chatbot. You're building a dynamic interface that adapts in real-time.
That’s the future I’m betting on. Stop prompting, start engineering.