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
statusorspan_kindover billions of rows is whatLowCardinality(String)is built for. Filtering byagent_id/session_idscans one narrow column instead of whole rows. - Cheap retention.
PARTITION BY toYYYYMM(start_time)lets you drop a month of traces with oneALTER 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]' openaifrom 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-serverThe 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
| Parameter | Type | Default | Description |
|---|---|---|---|
host | str | "localhost" | ClickHouse server host. |
port | int | 8123 | HTTP port. Use 8443 for TLS / ClickHouse Cloud. |
username | str | "default" | ClickHouse username. |
password | str | "" | ClickHouse password. |
database | str | "agno" | ClickHouse database name. Created lazily on a write that needs schema creation. |
secure | bool | False | Use HTTPS when True. |
client | Optional[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_table | Optional[str] | - | Override for the traces table name. |
spans_table | Optional[str] | - | Override for the spans table name. |
versions_table | Optional[str] | - | Override for the schema-versions table name. |
id | Optional[str] | - | Stable identifier for this DB instance. If omitted, derived deterministically from connection params. |
create_schema | bool | True | Allow lazy schema creation when a write needs missing database/tables. |