Skip to Content
DocsFrameworksAgentic UIsWith Vercel AI SDK

Using Vercel AI SDK

Mastra integrates with Vercel’s AI SDK to support model routing, React Hooks, and data streaming methods.

AI SDK v5 (beta)

Mastra also supports AI SDK v5 (beta) see the following section for v5 specific methods: Vercel AI SDK v5

⚠️

The code examples contained with this page assume you’re using the Next.js App Router at the root of your project, e.g., app rather than src/app.

Model routing

When creating agents in Mastra, you can specify any AI SDK-supported model.

agents/weather-agent.ts
import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), });

See Model Providers and Model Capabilities for more information.

React Hooks

Mastra supports AI SDK hooks for connecting frontend components directly to agents using HTTP streams.

Install the required AI SDK React package:

npm install @ai-sdk/react

Using the useChat() Hook

The useChat hook handles real-time chat interactions between your frontend and a Mastra agent, enabling you to send prompts and receive streaming responses over HTTP.

app/test/chat.tsx
"use client"; import { useChat } from "@ai-sdk/react"; export function Chat() { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: "api/chat" }); return ( <div> <pre>{JSON.stringify(messages, null, 2)}</pre> <form onSubmit={handleSubmit}> <input value={input} onChange={handleInputChange} placeholder="Name of city" /> </form> </div> ); }

Requests sent using the useChat hook are handled by a standard server route. This example shows how to define a POST route using a Next.js Route Handler.

app/api/chat/route.ts
import { mastra } from "../../mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); return stream.toDataStreamResponse(); }

When using useChat with agent memory, refer to the Agent Memory section for key implementation details.

Using the useCompletion() Hook

The useCompletion hook handles single-turn completions between your frontend and a Mastra agent, allowing you to send a prompt and receive a streamed response over HTTP.

app/test/completion.tsx
"use client"; import { useCompletion } from "@ai-sdk/react"; export function Completion() { const { completion, input, handleInputChange, handleSubmit } = useCompletion({ api: "api/completion" }); return ( <div> <form onSubmit={handleSubmit}> <input value={input} onChange={handleInputChange} placeholder="Name of city" /> </form> <p>Completion result: {completion}</p> </div> ); }

Requests sent using the useCompletion hook are handled by a standard server route. This example shows how to define a POST route using a Next.js Route Handler.

app/api/completion/route.ts
import { mastra } from "../../../mastra"; export async function POST(req: Request) { const { prompt } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream([{ role: "user", content: prompt }]); return stream.toDataStreamResponse(); }

Using the useObject() Hook

The useObject hook consumes streamed text from a Mastra agent and parses it into a structured JSON object based on a defined schema.

app/test/object.tsx
"use client"; import { experimental_useObject as useObject } from "@ai-sdk/react"; import { z } from "zod"; export function Object() { const { object, submit } = useObject({ api: "api/object", schema: z.object({ weather: z.string() }) }); return ( <div> <button onClick={() => submit("London")}>Generate</button> {object ? <pre>{JSON.stringify(object, null, 2)}</pre> : null} </div> ); }

Requests sent using the useObject hook are handled by a standard server route. This example shows how to define a POST route using a Next.js Route Handler.

app/api/object/route.ts
import { mastra } from "../../../mastra"; import { z } from "zod"; export async function POST(req: Request) { const body = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(body, { output: z.object({ weather: z.string() }) }); return stream.toTextStreamResponse(); }

Passing additional data with sendExtraMessageFields

The sendExtraMessageFields option allows you to pass additional data from the frontend to Mastra. This data is available on the server as RuntimeContext.

app/test/chat-extra.tsx
"use client"; import { useChat } from "@ai-sdk/react"; export function ChatExtra() { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: "/api/chat-extra", sendExtraMessageFields: true }); const handleFormSubmit = (e: React.FormEvent) => { e.preventDefault(); handleSubmit(e, { data: { userId: "user123", preferences: { language: "en", temperature: "celsius" } } }); }; return ( <div> <pre>{JSON.stringify(messages, null, 2)}</pre> <form onSubmit={handleFormSubmit}> <input value={input} onChange={handleInputChange} placeholder="Name of city" /> </form> </div> ); }

Requests sent using sendExtraMessageFields are handled by a standard server route. This example shows how to extract the custom data and populate a RuntimeContext instance.

app/api/chat-extra/route.ts
import { mastra } from "../../../mastra"; import { RuntimeContext } from "@mastra/core/runtime-context"; export async function POST(req: Request) { const { messages, data } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const runtimeContext = new RuntimeContext(); if (data) { for (const [key, value] of Object.entries(data)) { runtimeContext.set(key, value); } } const stream = await myAgent.stream(messages, { runtimeContext }); return stream.toDataStreamResponse(); }

Handling runtimeContext with server.middleware

You can also populate the RuntimeContext by reading custom data in a server middleware:

mastra/index.ts
import { Mastra } from "@mastra/core/mastra"; export const mastra = new Mastra({ agents: { weatherAgent }, server: { middleware: [ async (c, next) => { const runtimeContext = c.get("runtimeContext"); if (c.req.method === "POST") { try { const clonedReq = c.req.raw.clone(); const body = await clonedReq.json(); if (body?.data) { for (const [key, value] of Object.entries(body.data)) { runtimeContext.set(key, value); } } } catch { } } await next(); }, ], }, });

You can then access this data in your tools via the runtimeContext parameter. See the Runtime Context documentation for more details.

Streaming data

The ai package provides utilities for managing custom data streams. In some cases, you may want to send structured updates or annotations to the client using an agent’s dataStream.

Install the required package:

npm install ai

Using createDataStream()

The createDataStream function allows you to stream additional data to the client.

mastra/agents/weather-agent.ts
import { createDataStream } from "ai"; import { Agent } from "@mastra/core/agent"; export const weatherAgent = new Agent({...}); createDataStream({ async execute(dataStream) { dataStream.writeData({ value: "Hello" }); dataStream.writeMessageAnnotation({ type: "status", value: "processing" }); const agentStream = await weatherAgent.stream("What is the weather"); agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error}` });

Using createDataStreamResponse()

The createDataStreamResponse function creates a response object that streams data to the client.

app/api/chat-stream/route.ts
import { mastra } from "../../../mastra"; import { createDataStreamResponse } from "ai"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const agentStream = await myAgent.stream(messages); const response = createDataStreamResponse({ status: 200, statusText: "OK", headers: { "Custom-Header": "value" }, async execute(dataStream) { dataStream.writeData({ value: "Hello" }); dataStream.writeMessageAnnotation({ type: "status", value: "processing" }); agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error}` }); return response; }

Vercel AI SDK v5

This guide covers Mastra-specific considerations when migrating from AI SDK v4 to v5 beta.

Please add any feedback or bug reports to the AI SDK v5 mega issue in Github.

Official migration guide

Follow the official AI SDK v5 Migration Guide for all AI SDK core breaking changes, package updates, and API changes.

This guide covers only the Mastra-specific aspects of the migration.

  • Data compatibility: New data stored in v5 format will no longer work if you downgrade from the beta
  • Backup recommendation: Keep DB backups from before you upgrade to v5 beta
  • Production use: Wait for the AI SDK v5 stable release before using in production applications
  • Prerelease status: The Mastra ai-v5 tag is a prerelease version and may have bugs

Memory and Storage

Mastra automatically handles AI SDK v4 data using its internal MessageList class, which manages format conversion—including v4 to v5. No database migrations are required; your existing messages are translated on the fly and continue working after you upgrade.

Migration strategy

Migrating to AI SDK v5 with Mastra involves updating both your backend (Mastra server) and frontend. We provide a compatibility mode to handle stream format conversion during the transition.

Upgrade dependencies

Install the @ai-v5 prerelease version of all Mastra packages:

npm install mastra@ai-v5 @mastra/core@ai-v5 @mastra/memory@ai-v5

Configure your Mastra instance with v4 compatibility so your frontend, and the Mastra Playground will continue to work:

mastra/index.ts
import { Mastra } from "@mastra/core/mastra"; import { weatherAgent } from "./agents/weather-agent"; export const mastra = new Mastra({ agents: { weatherAgent }, aiSdkCompat: 'v4', });

Enabling stream compatibility

If your frontend calls a Mastra agent using a custom API route, wrap the toUIMessageStreamResponse() result with createV4CompatibleResponse to maintain AI SDK v4 compatibility.

app/api/chat/route.ts
import { mastra } from "../../../mastra"; import { createV4CompatibleResponse } from "@mastra/core/agent"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); return createV4CompatibleResponse(stream.toUIMessageStreamResponse().body!); }

Frontend upgrade

When you’re ready, remove the compatibility flag and upgrade your frontend:

  1. Remove aiSdkCompat: 'v4' from your Mastra configuration
  2. Follow the AI SDK guide on upgrading your frontend dependencies
  3. Update your frontend code for v5 breaking changes