# Migration from Web URL: /docs/react-native/migration Migrate an existing @assistant-ui/react app to React Native. If you already have an assistant-ui web app, most of your code transfers directly. The runtime core is shared between `@assistant-ui/react` and `@assistant-ui/react-native` via `@assistant-ui/core` — only the UI layer changes. What stays the same \[#what-stays-the-same] * **Runtime setup** — `useChatRuntime`, `useLocalRuntime`, `ChatModelAdapter`, and all runtime options work identically. * **AI SDK integration** — `@assistant-ui/react-ai-sdk` works with React Native. Your `useChatRuntime` + `AssistantChatTransport` setup transfers directly. * **Tool definitions** — `useAssistantTool`, `makeAssistantTool`, and tool UI renderers use the same API. * **State hooks** — `useAuiState`, `useAui`, and selector patterns are the same. * **Backend code** — Your API routes, streaming endpoints, and server-side logic need zero changes. What changes \[#what-changes] | Web (`@assistant-ui/react`) | React Native (`@assistant-ui/react-native`) | | ----------------------------------------- | ---------------------------------------------------- | | `AssistantRuntimeProvider` | `AssistantRuntimeProvider` (same name) | | DOM primitives (`div`, `button`, `input`) | Native primitives (`View`, `Pressable`, `TextInput`) | | CSS / Tailwind styling | React Native `StyleSheet` or inline styles | | `@assistant-ui/ui` (shadcn components) | Build your own native UI with primitives | Step-by-step \[#step-by-step] Install the React Native package \[#install-the-react-native-package] ```sh npx expo install @assistant-ui/react-native ``` Keep your runtime hook \[#keep-your-runtime-hook] Your `useChatRuntime` setup works as-is — no changes needed: ```tsx title="hooks/use-app-runtime.ts" // This file is identical to your web version import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/react-ai-sdk"; export function useAppRuntime() { return useChatRuntime({ transport: new AssistantChatTransport({ api: "/api/chat", }), }); } ``` If you use a monorepo, you can share this file between web and native projects directly. Replace the provider \[#replace-the-provider] ```tsx // Before (web) // import { AssistantRuntimeProvider } from "@assistant-ui/react"; // After (React Native) — same component name, different package import { AssistantRuntimeProvider } from "@assistant-ui/react-native"; export default function App() { const runtime = useAppRuntime(); return ( {/* your native UI */} ); } ``` Rebuild the UI layer \[#rebuild-the-ui-layer] This is the main migration effort. Web components (`Thread`, `ThreadList` from `@assistant-ui/ui`) don't render in React Native. Replace them with native primitives: ```tsx // Web — DOM-based // import { Thread } from "@/components/assistant-ui/thread"; // React Native — use primitives or build custom import { ThreadPrimitive, ComposerPrimitive, } from "@assistant-ui/react-native"; import { View, Text } from "react-native"; function ChatScreen() { return ( ( {message.content.filter((p) => p.type === "text").map((p) => p.text).join("\n")} )} /> ); } ``` See the [Primitives reference](/docs/react-native/primitives) for the full list of available components. Monorepo code sharing \[#monorepo-code-sharing] In a monorepo, you can share everything except the UI layer: ``` packages/ shared/ hooks/ ← useAppRuntime with useChatRuntime (shared) tools/ ← tool definitions (shared) web/ components/ ← DOM-based UI native/ components/ ← React Native UI ``` The runtime hook, tool definitions, and backend code are platform-agnostic. Only the UI components need separate implementations for web and native.