Agent Conversation Storage
Agent chat history is stored in browser localStorage by default. Server-side persistence is off until you enable it at runtime:
AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=autoAGENT_CONVERSATION_STORE accepts auto, agentstate, d1,
durable-object, clickhouse, postgres, memory, or local. The deprecated
NEXT_PUBLIC_FEATURE_CONVERSATION_DB=true still enables auto, but do not use
it for new deployments.
Server stores require authenticated user identity by default. If the current request is unauthenticated, the browser keeps using localStorage.
Auto Selection
Section titled “Auto Selection”auto chooses the first available backend in this order:
- AgentState when
AGENTSTATE_API_KEYis set. - D1 when
CONVERSATIONS_D1is bound. - Durable Object when
AGENT_CONVERSATIONS_DOis bound. - Postgres when
DATABASE_URL,POSTGRES_URL, orPOSTGRES_PRISMA_URLis set. - ClickHouse only when
CLICKHOUSE_AGENT_CONVERSATIONS_TABLEis explicitly set. - Memory in development/test only.
Production auto fails closed when no persistent backend is configured.
AgentState
Section titled “AgentState”AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=agentstateAGENTSTATE_API_KEY=as_live_xxxAGENTSTATE_API_BASE=https://agentstate.app/apiThe app uses direct REST calls. The AgentState record stores
external_id = threadId, metadata.user_id, model/provider/host fields, and
raw UI message metadata. Normal completed turns append new messages. If an edit
or regeneration changes already-persisted messages, the adapter deletes and
recreates the AgentState conversation with the same external_id.
Cloudflare D1
Section titled “Cloudflare D1”AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=d1CHM_AUTH_PROVIDER=clerkNEXT_PUBLIC_AUTH_PROVIDER=clerkCLERK_SECRET_KEY=sk_live_xxxSetup:
bun run cf:setup-conversationsbun run cf:migrate-conversationsRequired binding: CONVERSATIONS_D1. The migration path is
apps/dashboard/src/db/conversations-migrations. D1 is recommended for ordinary
Cloudflare conversation history because it is a managed database with standard
schema management, query tooling, import/export, and direct operational access.
Deploy requirements
Wrangler deploys need a concrete D1 UUID for active bindings:
- The checked-in config keeps the conversation binding unprovisioned until setup runs.
- During deploy,
scripts/prepare-dashboard-wrangler.tsremoves optional bindings without a UUID.- To enable it in CI, set
CONVERSATIONS_D1_DATABASE_ID=<uuid>; locally, runbun run cf:setup-conversations.- The Cloudflare API token needs Workers deploy permissions plus D1 edit/read access.
Durable Object
Section titled “Durable Object”AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=durable-objectAGENT_CONVERSATIONS_DO_BINDING=AGENT_CONVERSATIONS_DOThe worker exports AgentConversationDurableObject and Wrangler config creates
a SQLite-backed Durable Object namespace with new_sqlite_classes. The app uses
one Durable Object per user id.
Durable Objects are supported for deployments that want per-user coordination or strictly colocated state. For ordinary queryable history, prefer D1: D1 is easier to inspect, migrate, export, and operate outside a single object.
ClickHouse
Section titled “ClickHouse”AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=clickhouseCLICKHOUSE_AGENT_CONVERSATIONS_TABLE=system.agent_conversationsCLICKHOUSE_AGENT_CONVERSATIONS_AUTO_CREATE=trueSetup:
bun run setup:agent-conversations-clickhouseThe ClickHouse user must be allowed to CREATE TABLE when auto-create is on and
INSERT/SELECT on the conversation table. Deletes are tombstone rows. The
table uses ReplacingMergeTree, native numeric/date columns, LowCardinality
strings for repeated fields, and JSON strings for message and metadata payloads.
Writes use async inserts with wait_for_async_insert=1.
Postgres
Section titled “Postgres”AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=postgresDATABASE_URL=postgresql://user:password@host:5432/dbPOSTGRES_URL and POSTGRES_PRISMA_URL are also accepted. The runtime creates
the conversations table and indexes if they do not exist. The database user
needs CREATE TABLE, CREATE INDEX, SELECT, INSERT, UPDATE, and
DELETE on the target schema.
Memory And Local
Section titled “Memory And Local”AGENT_CONVERSATION_STORE=locallocal keeps browser localStorage and is the default when persistence is off.
AGENT_CONVERSATION_PERSISTENCE=trueAGENT_CONVERSATION_STORE=memorymemory is only for development and tests. It is never accepted as production
persistent storage because data is lost on process restart.
Fallbacks
Section titled “Fallbacks”- Persistence off: browser localStorage.
- Server persistence on but user unauthenticated: browser localStorage.
autowith no backend in development/test: memory.autowith no backend in production: disabled until a persistent backend is configured.