Integrate Mastra in your React + Vite project
In this guide, you'll build a tool-calling AI agent using Mastra, then connect it to React by calling the agent directly from Mastra's standalone server.
You'll use AI SDK UI and AI Elements to create a beautiful, interactive chat experience.
Before you beginDirect link to Before you begin
- You'll need an API key from a supported model provider. If you don't have a preference, use OpenAI.
- Install Node.js
v22.13.0or later
Create a new React + Vite app (optional)Direct link to Create a new React + Vite app (optional)
If you already have a React + Vite app using Tailwind, skip to the next step.
Project scaffoldDirect link to Project scaffold
Run the following command to create a new React + Vite app:
- npm
- pnpm
- yarn
- bun
npm create vite@latest mastra-react -- --template react-ts
cd mastra-react
pnpm create vite mastra-react --template react-ts
cd mastra-react
yarn create vite mastra-react --template react-ts
cd mastra-react
bun create vite mastra-react --template react-ts
cd mastra-react
This creates a project called mastra-react, but you can replace it with any name you want.
TailwindDirect link to Tailwind
Next, install Tailwind:
- npm
- pnpm
- yarn
- bun
npm install tailwindcss @tailwindcss/vite
pnpm add tailwindcss @tailwindcss/vite
yarn add tailwindcss @tailwindcss/vite
bun add tailwindcss @tailwindcss/vite
Configure the Vite plugins:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path"
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
Replace everything in src/index.css with the following:
@import "tailwindcss";
Add these compilerOptions to tsconfig.json:
{
// ...
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Edit tsconfig.app.json to resolve paths:
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
// ...
}
}
Initialize MastraDirect link to Initialize Mastra
Run mastra init. When prompted, choose a provider (e.g. OpenAI) and enter your key:
- npm
- pnpm
- yarn
- bun
cd mastra-react
npx mastra@beta init
cd mastra-react
pnpm dlx mastra@beta init
cd mastra-react
yarn dlx mastra@beta init
cd mastra-react
bunx mastra@beta init
This creates a src/mastra folder with an example weather agent and the following files:
index.ts- Mastra config, including memorytools/weather-tool.ts- a tool to fetch weather for a given locationagents/weather-agent.ts- a weather agent with a prompt that uses the tool
You'll call weather-agent.ts from your chat UI in the next steps.
Install AI SDK UI & AI ElementsDirect link to Install AI SDK UI & AI Elements
Install AI SDK UI along with the Mastra adapter:
- npm
- pnpm
- yarn
- bun
npm install @mastra/ai-sdk@beta @ai-sdk/react ai
pnpm add @mastra/ai-sdk@beta @ai-sdk/react ai
yarn add @mastra/ai-sdk@beta @ai-sdk/react ai
bun add @mastra/ai-sdk@beta @ai-sdk/react ai
Next, initialize AI Elements. When prompted, choose the default options:
- npm
- pnpm
- yarn
- bun
npx ai-elements@latest
pnpm dlx ai-elements@latest
yarn dlx ai-elements@latest
bunx ai-elements@latest
This downloads the entire AI Elements UI component library into a @/components/ai-elements folder.
Create a chat routeDirect link to Create a chat route
Open src/mastra/index.ts and add a chatRoute() to your config. This creates an API route your React frontend can call for AI SDK-compatible chat responses, which you’ll use with useChat() next.
import { Mastra } from '@mastra/core/mastra';
// Existing imports...
import { chatRoute } from "@mastra/ai-sdk"
export const mastra = new Mastra({
// Existing config...
server: {
apiRoutes: [
chatRoute({
path: '/chat/:agentId'
})
]
}
});
Add the chat UIDirect link to Add the chat UI
Replace the src/App.tsx file to create a chat interface:
import * as React from 'react';
import { DefaultChatTransport, type ToolUIPart } from 'ai';
import { useChat } from '@ai-sdk/react';
import {
PromptInput,
PromptInputBody,
PromptInputTextarea,
} from '@/components/ai-elements/prompt-input';
import {
Conversation,
ConversationContent,
ConversationScrollButton,
} from '@/components/ai-elements/conversation';
import {
Message,
MessageContent,
MessageResponse
} from '@/components/ai-elements/message';
import {
Tool,
ToolHeader,
ToolContent,
ToolInput,
ToolOutput,
} from '@/components/ai-elements/tool';
export default function App() {
const [input, setInput] = React.useState<string>('');
const { messages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({
api: 'http://localhost:4111/chat/weather-agent',
}),
});
const handleSubmit = async () => {
if (!input.trim()) return;
sendMessage({ text: input });
setInput('');
};
return (
<div className="max-w-4xl mx-auto p-6 relative size-full h-screen">
<div className="flex flex-col h-full">
<Conversation className="h-full">
<ConversationContent>
{messages.map((message) => (
<div key={message.id}>
{message.parts?.map((part, i) => {
if (part.type === 'text') {
return (
<Message
key={`${message.id}-${i}`}
from={message.role}>
<MessageContent>
<MessageResponse>{part.text}</MessageResponse>
</MessageContent>
</Message>
);
}
if (part.type?.startsWith('tool-')) {
return (
<Tool key={`${message.id}-${i}`}>
<ToolHeader
type={(part as ToolUIPart).type}
state={(part as ToolUIPart).state || 'output-available'}
className="cursor-pointer"
/>
<ToolContent>
<ToolInput input={(part as ToolUIPart).input || {}} />
<ToolOutput
output={(part as ToolUIPart).output}
errorText={(part as ToolUIPart).errorText}
/>
</ToolContent>
</Tool>
);
}
return null;
})}
</div>
))}
<ConversationScrollButton />
</ConversationContent>
</Conversation>
<PromptInput onSubmit={handleSubmit} className="mt-20">
<PromptInputBody>
<PromptInputTextarea
onChange={(e) => setInput(e.target.value)}
className="md:leading-10"
value={input}
placeholder="Ask about the weather..."
disabled={status !== 'ready'}
/>
</PromptInputBody>
</PromptInput>
</div>
</div>
);
}
This component connects useChat() to the chat/weather-agent endpoint, sending prompts there and streaming the response back in chunks.
It renders the response text using the <MessageResponse> component, and shows any tool invocations with the <Tool> component.
Test your agentDirect link to Test your agent
In order to test your agent with the chat interface, you need to run both the Mastra server and the Vite development server.
-
Start the Mastra development server:
npx mastra dev -
In a separate terminal window, start the Vite development server:
npm run dev -
Open your application at http://localhost:5173
-
Try asking about the weather. If your API key is set up correctly, you'll get a response
Next stepsDirect link to Next steps
Congratulations on building your Mastra agent with React! 🎉
From here, you can extend the project with your own tools and logic:
When you're ready, read more about how Mastra integrates with AI SDK UI and React, and how to deploy your agent anywhere: