ClickHouse

Use ClickHouse as a dedicated traces backend for high-volume OLAP scans.

Agno supports using ClickHouse as a database with the ClickhouseDb class.

ClickhouseDb is traces-only. It implements upsert_trace, create_spans, and the read paths for traces and spans. Sessions, memories, knowledge, evals, and component configs are not stored here. Pair it with a row-store (Postgres, MySQL, MongoDB) for that data.

Why ClickHouse only for traces

ClickHouse is an OLAP columnar engine. It is designed for the workload traces actually produce:

  • Append-heavy ingest. Spans arrive continuously. ClickHouse inserts coalesce into large columnar parts.
  • Time-bucketed aggregates. Trace dashboards group by minute, hour, day. Columnar storage scans only the columns the query touches.
  • Low-cardinality filters. Filtering by status or span_kind over billions of rows is what LowCardinality(String) is built for. Filtering by agent_id / session_id scans one narrow column instead of whole rows.
  • Cheap retention. PARTITION BY toYYYYMM(start_time) lets you drop a month of traces with one ALTER TABLE.

Agno's ClickhouseDb adapter implements trace and span storage. Its write methods for sessions, memories, knowledge, and evals raise NotImplementedError. Use a separate database for those records; the adapter's traces-only scope determines which Agno features it can store.

Usage

Run the local PostgreSQL setup on port 5532 for sessions, then start ClickHouse using the command below. Save the code as clickhouse_for_traces.py and serve it with uvicorn clickhouse_for_traces:app --port 7777.

Start in a virtual environment and set the model key before running the example.

Set OpenAI Key

Set your OPENAI_API_KEY as an environment variable. You can get one from OpenAI.

export OPENAI_API_KEY=sk-***

Install the required packages:

uv pip install -U 'agno[os]' clickhouse-connect 'psycopg[binary]' openai
clickhouse_for_traces.py
from agno.agent import Agent
from agno.db.clickhouse import ClickhouseDb
from agno.db.postgres import PostgresDb
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS
from agno.tools.hackernews import HackerNewsTools
from agno.tracing import setup_tracing

# Row-store for sessions, memories, evals.
primary_db = PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai")

# OLAP store dedicated to traces.
traces_db = ClickhouseDb(
    host="localhost",
    port=8123,
    username="ai",
    password="ai",
    database="agno_traces",
)

# Batch processing is strongly recommended for ClickHouse.
setup_tracing(
    db=traces_db,
    batch_processing=True,
    max_queue_size=2048,
    max_export_batch_size=512,
    schedule_delay_millis=5000,
)

agent = Agent(
    name="HackerNews Agent",
    model=OpenAIResponses(id="gpt-5.2"),
    tools=[HackerNewsTools()],
    instructions="You are a hacker news agent. Answer questions concisely.",
    markdown=True,
    db=primary_db,
)

agent_os = AgentOS(
    agents=[agent],
    db=traces_db,
)
app = agent_os.get_app()

Always enable batch_processing=True with ClickHouse. The default SimpleSpanProcessor issues one insert per span and will hit the server's parts_to_throw_insert limit under load. ClickHouse strongly prefers a smaller number of larger inserts.

Run ClickHouse

Install Docker Desktop and run ClickHouse on port 8123 (HTTP) and 9000 (native) using:

docker run -d \
  --name clickhouse \
  -e CLICKHOUSE_DB=agno_traces \
  -e CLICKHOUSE_USER=ai \
  -e CLICKHOUSE_PASSWORD=ai \
  -p 8123:8123 \
  -p 9000:9000 \
  clickhouse/clickhouse-server

The command above is the minimum to get running. Data in the container survives a restart of that same container; use a mounted data volume to retain it when the container is removed or replaced. For a persistent local setup with mounted volumes, use the cookbook script cookbook/scripts/run_clickhouse.sh.

ClickHouse Cloud

traces_db = ClickhouseDb(
    host="<your-host>.clickhouse.cloud",
    port=8443,
    username="default",
    password="<password>",
    database="agno_traces",
    secure=True,
)

The Agent’s explicit primary_db remains its session store. AgentOS(db=traces_db) also makes ClickHouse the default for components without an explicit database and for OS-level storage, whose non-tracing operations are unsupported by this adapter. Give every session-bearing component an appropriate database. Select the traces database ID when reading ClickHouse traces through the API.

Params

ParameterTypeDefaultDescription
hoststr"localhost"ClickHouse server host.
portint8123HTTP port. Use 8443 for TLS / ClickHouse Cloud.
usernamestr"default"ClickHouse username.
passwordstr""ClickHouse password.
databasestr"agno"ClickHouse database name. Created lazily on a write that needs schema creation.
secureboolFalseUse HTTPS when True.
clientOptional[Client]-Pre-built clickhouse_connect client; skips client construction. database still selects the table namespace, and host, port, username, and database still determine the default ID.
traces_tableOptional[str]-Override for the traces table name.
spans_tableOptional[str]-Override for the spans table name.
versions_tableOptional[str]-Override for the schema-versions table name.
idOptional[str]-Stable identifier for this DB instance. If omitted, derived deterministically from connection params.
create_schemaboolTrueAllow lazy schema creation when a write needs missing database/tables.

Developer Resources