# Getting Started
URL: /docs/react-native
Build AI chat interfaces for iOS and Android with @assistant-ui/react-native.
Quick Start \[#quick-start]
The fastest way to get started with assistant-ui for React Native.
Create a new project \[#create-a-new-project]
```sh
npx assistant-ui@latest create --example with-expo my-chat-app
cd my-chat-app
```
Configure API endpoint \[#configure-api-endpoint]
Create a `.env` file pointing to your chat API:
```
EXPO_PUBLIC_CHAT_ENDPOINT_URL="http://localhost:3000/api/chat"
```
Start the app \[#start-the-app]
```sh
npx expo start
```
Manual Setup \[#manual-setup]
If you prefer to add assistant-ui to an existing Expo project, follow these steps.
Install dependencies \[#install-dependencies]
```sh
npx expo install @assistant-ui/react-native @assistant-ui/react-ai-sdk
```
Setup Backend Endpoint \[#setup-backend-endpoint]
Create a backend API route using the Vercel AI SDK. This is the same endpoint you'd use with `@assistant-ui/react` on the web:
<>
```ts title="app/api/chat/route.ts"
import { openai } from "@ai-sdk/openai";
import { convertToModelMessages, streamText } from "ai";
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-4o-mini"),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
```
```ts title="app/api/chat/route.ts"
import { anthropic } from "@ai-sdk/anthropic";
import { convertToModelMessages, streamText } from "ai";
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: anthropic("claude-sonnet-4-20250514"),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
```
```ts title="app/api/chat/route.ts"
import { google } from "@ai-sdk/google";
import { convertToModelMessages, streamText } from "ai";
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: google("gemini-2.0-flash"),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
```
>
This is the same backend you'd use with `@assistant-ui/react` on the web. If you already have an API route, you can reuse it as-is.
Set up the runtime \[#set-up-the-runtime]
```tsx title="hooks/use-app-runtime.ts"
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/react-ai-sdk";
const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3000";
export function useAppRuntime() {
return useChatRuntime({
transport: new AssistantChatTransport({
api: `${API_URL}/api/chat`,
}),
});
}
```
Use it in your app \[#use-it-in-your-app]
Wrap your app with `AssistantRuntimeProvider` and build your chat UI:
```tsx title="app/index.tsx"
import {
AssistantRuntimeProvider,
useAuiState,
useAui,
} from "@assistant-ui/react-native";
import type { ThreadMessage } from "@assistant-ui/react-native";
import {
View,
Text,
TextInput,
FlatList,
Pressable,
KeyboardAvoidingView,
Platform,
} from "react-native";
import { useAppRuntime } from "@/hooks/use-app-runtime";
function MessageBubble({ message }: { message: ThreadMessage }) {
const isUser = message.role === "user";
const text = message.content
.filter((p) => p.type === "text")
.map((p) => ("text" in p ? p.text : ""))
.join("\n");
return (
{text}
);
}
function Composer() {
const aui = useAui();
const text = useAuiState((s) => s.composer.text);
const isEmpty = useAuiState((s) => s.composer.isEmpty);
return (
aui.composer().setText(t)}
placeholder="Message..."
multiline
style={{
flex: 1,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 20,
paddingHorizontal: 16,
paddingVertical: 10,
maxHeight: 120,
}}
/>
aui.composer().send()}
disabled={isEmpty}
style={{
marginLeft: 8,
backgroundColor: !isEmpty ? "#007aff" : "#ccc",
borderRadius: 20,
width: 36,
height: 36,
justifyContent: "center",
alignItems: "center",
}}
>
↑
);
}
function ChatScreen() {
const messages = useAuiState(
(s) => s.thread.messages,
) as ThreadMessage[];
return (
m.id}
renderItem={({ item }) => }
/>
);
}
export default function App() {
const runtime = useAppRuntime();
return (
);
}
```
What's Next? \[#whats-next]