Skip to main content
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) and the merge tree index are built for. Filtering by agent_id / session_id rides the merge tree’s primary index.
  • Cheap retention. PARTITION BY toYYYYMM(start_time) lets you drop a month of traces with one ALTER TABLE.
What ClickHouse is not built for:
WorkloadWhy it’s a poor fit
Row-level updatesMutations are asynchronous and heavy. There is no OLTP UPDATE.
Multi-row transactionsNo transaction boundaries across rows.
Single-row reads by primary keyThe merge tree is optimized for range scans, not point lookups.
Session and memory storage hit all three of those patterns, which is why Agno uses a row-store for them and reserves ClickHouse for tracing.

Usage

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=ai \
  -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. Traces don’t persist across container restarts. 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,
)

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 at startup if missing.
secureboolFalseUse HTTPS when True.
clientOptional[Client]-Pre-built clickhouse_connect client. When provided, the connection arguments above are ignored.
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_schemaboolTrueCreate database and tables on startup if missing.

Developer Resources