---
title: AI SDK Chat Persistence
description: Vercel AI SDK chat with thread persistence — open-source React example combining the AI SDK and assistant-ui for streaming, thread management, and message history.
---

import { Base } from "@/components/examples/base";

<div className="not-prose h-[600px]">
  <Base />
</div>

## Overview

This example demonstrates integrating assistant-ui with the Vercel AI SDK for building production-ready chat interfaces. It showcases a complete chat application with thread management, message persistence, and a collapsible sidebar for conversation history.

## Features

- **AI SDK Integration**: Seamless connection with Vercel's `ai` package
- **Thread Management**: Create, switch, and delete conversation threads
- **Collapsible Sidebar**: Toggle sidebar visibility for focused chat
- **Model Picker**: Switch between different AI models
- **Responsive Design**: Mobile-friendly with sheet-based navigation
- **Real-time Streaming**: Live message streaming with loading states

## Quick Start

```bash
npm install @assistant-ui/react @assistant-ui/react-ai-sdk ai@^6 @ai-sdk/react@^3 @ai-sdk/openai
```

## Code

### Client Component

```tsx
"use client";

import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { Thread } from "@/components/assistant-ui/thread";
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";

export default function Chat() {
  const runtime = useChatRuntime();

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      <div className="flex h-full">
        <Sidebar />
        <main className="flex-1">
          <Thread />
        </main>
      </div>
    </AssistantRuntimeProvider>
  );
}
```

### API Route

```ts
// app/api/chat/route.ts
import { openai } from "@ai-sdk/openai";
import { streamText, convertToModelMessages } from "ai";
import type { UIMessage } from "ai";

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();

  const result = streamText({
    model: openai("gpt-5.4-nano"),
    messages: await convertToModelMessages(messages),
    // Optional: Add system prompt
    system: "You are a helpful assistant.",
  });

  return result.toUIMessageStreamResponse();
}
```

### Key Integration Points

| Hook/Function | Purpose |
|---------------|---------|
| `useChatRuntime` | Connects AI SDK to assistant-ui |
| `streamText` | Server-side streaming response generation |
| `toUIMessageStreamResponse` | Converts stream to Response object |

### Adding Persistence

<Callout type="info">
  `useChatRuntime()` on its own does not persist threads across reloads. The snippet below is a minimal server-side save sketch. For full thread persistence (history reload, branching) use [Assistant Cloud](/docs/cloud) or the [custom persistence adapter](/docs/integrations/persistence/custom-adapter).
</Callout>

To persist conversations, add a database and modify the API route. `useChatRuntime` sends the current thread id as `id` in the request body, so you can read it alongside `messages`:

```ts
// In your POST /api/chat handler:
const { id: threadId, messages } = await req.json();

// Save the latest user message
const last = messages.at(-1);
if (last) {
  await db.messages.create({
    threadId,
    role: last.role,
    parts: last.parts,
  });
}

// Load messages when opening a thread (e.g., from a ThreadHistoryAdapter):
const savedMessages = await db.messages.findMany({ threadId });
```

## Source

<SourceLink href="https://github.com/assistant-ui/assistant-ui/blob/main/apps/docs/components/examples/base.tsx" />
