---
title: "Persistence & history"
description: "How the user-bound store persists turns, computes conversation counts, loads history, and limits model context."
---

The default Drizzle store writes conversations and messages to Postgres. It is
constructed per request bound to the verified user.

## Drizzle schema

- `chat_conversations`: id, user id, title, metadata, created and updated times.
- `chat_messages`: id, conversation id, role, canonical parts, text projection,
  model, and created time.

`messageCount` is not stored on the conversation row. The Drizzle
`listConversations` query computes it from messages for the history sidebar.

## Turn persistence

The handler persists the latest user message, streams the response, then calls
`saveTurn` for the completed assistant turn. Store implementations must verify
ownership and deduplicate stable message ids.

```ts
await store.saveTurn({
  conversationId,
  messages: finalMessages,
  model,
  usage,
});
```

The complete `parts` array is authoritative. The text column is a denormalized
projection for previews/search.

## History routes

- `GET /history` calls `listConversations`.
- `GET /history/:conversationId` calls `listMessages`, returns chronological
  messages, and re-signs stored attachments when storage is configured.

The Drizzle store supports `limit` and `before` pagination and caps pages at 100.

> **Warning**
>
> The current hosted store ignores `ListMessagesOptions` and fetches the complete
> conversation. Do not rely on `before` pagination when using that adapter until
> hosted pagination is implemented.

## Model context versus stored history

`maxHistoryMessages` (default 30) and `maxMessageChars` (default 4000) affect
what is sent to the model. They do not delete stored messages or hide history
from the UI.

```ts
export const { GET, POST, DELETE } = createChatHandler({
  getUserId: getChatUserId,
  model,
  store: createDrizzleChatStore(),
  maxHistoryMessages: 40,
  maxMessageChars: 6000,
});
```

Set `maxMessageChars: 0` to disable the character cap. Use
`summarizeHistory` when dropped early messages must remain available as condensed,
non-authoritative background.

See [`ChatStore`](/docs/api/chat-store) for the full contract.
