2026-10-28 · 14:40–15:40
chDB

What is chDB,
and what can you
use it for?

ClickHouse, as a library — and where people put it
Auxten Wang · ClickHouse · Creator of chDB@auxten
ABOUT
Auxten Wang

Auxten Wang

@auxten · auxten.com

Started chDB as a side project in 2023
chDB joined ClickHouse in 2024
Today: embedded ClickHouse — Python, browser, agents, Postgres
chDB
ClickHouse
THE ANSWER

chDB is ClickHouse as a library

CLICKHOUSE SERVER

Your app

——→
network
port 8123

ClickHouse

a process you run
Shared, always on, many users
Somebody installs and operates it
CHDB

Your app's process

your code

——→
function call

ClickHouse engine

pip install chdb — nothing to run
Same SQL, same engine, inside your program
Think SQLite — but the engine inside is ClickHouse.
LIVE DEMO

This slide is running ClickHouse

Not a screenshot. The engine is compiled to WebAssembly and loaded in this browser tab.

enginetotal
26.5.1.14999999950000000
recorded77 ms · 100,000,000 rows · laptop Chrome, 2026-10-26
No server.
No install.
No network round-trip.
npm i chdb-wasm
also: wasm.chdb.io
engine: idle
ORIGIN

It started as a wild idea

"What if ClickHouse were a pip install?"

2023
Side project: ClickHouse compiled into a Python module
2024
Joins ClickHouse. DataFrames read without copying
2025
CI, notebooks, ML pipelines, agents adopt it
2026
v4: Pandas API, browser, Postgres, 11 languages
The idea was small. The engine underneath wasn't.
ADOPTION

Then it caught on

chDB PyPI weekly downloads, March 2023 to October 2026

PyPI downloads per week, Mar 2023 → Oct 2026 · week of 2026-10-18: 1,002,552

~1.0M
PyPI downloads last week
3.37M
PyPI downloads last month
2.9k
GitHub stars · chdb-io/chdb

pypistats.org + GitHub API, fetched 2026-10-26

THE MAP

One engine, many homes

PART 1 · WHAT PEOPLE DO WITH IT

Part 1: what people do with it

USE CASE · CI

Your tests don't need a ClickHouse server

BEFORE · CI.YML
services: clickhouse: image: clickhouse/clickhouse-server ports: ["8123:8123"] # + health check, wait loop, flaky timeouts
AFTER · TEST CODE
import clickhouse_connect # was: host="localhost", port=8123 c = clickhouse_connect.get_client( dsn="chdb://") c.query("SELECT count() FROM t")

clickhouse-connect 1.11 + chdb 4.4 · ran 2026-10-26

No Docker in CI
Same client, same SQL
Starts in-process, instantly
Every test run used to start a database. Now it imports one.
USE CASE · PYTHON DATA

SQL on the DataFrame you already have

import chdb, pandas as pd df = pd.read_csv("sales.csv") # any DataFrame chdb.query(""" SELECT city, quantile(0.9)(amount) FROM Python(df) GROUP BY city""", "DataFrame") # back to pandas

IN

DataFrame, Arrow table, dict — read in place

MIDDLE

Full ClickHouse SQL, all cores

OUT

DataFrame, Arrow, Parquet, CSV…
Keep pandas for what it's good at. Hand the heavy SQL to ClickHouse.
USE CASE · ML

Feature prep without a warehouse

RAW LOGS

Parquet · S3 · local
→

chDB SQL

quantiles · windows · joins
→

DATAFRAME

→ numpy → model.fit
feats = chdb.query(""" SELECT url, count() AS hits, quantile(0.95)(latency_ms) AS p95_ms, avg(status >= 500) AS error_rate FROM file('access_log.parquet') GROUP BY url""", "DataFrame") model.fit(feats[["hits", "p95_ms", "error_rate"]])
10M log rows →
4.87M feature rows
1.7 s chDB
6.0 s pandas
laptop · single run
USE CASE · AI AGENTS

An agent's database: one SQL tool

from chdb.agents import ChDBTool tool = ChDBTool(read_only=True, max_rows=100) # tools the agent sees: # run_select_query · list_tables # describe_table · attach_file …
Read-only by default — writes raise an error
Row, byte and time limits built in
LlamaIndex · Pydantic AI · smolagents · MCP
 agent session
How many customers per tier in last quarter's CRM export?
Querying the archive directly…SELECT tier, count() FROM file('crm_exports.tar :: users_*.csv') GROUP BY tier
enterprise 32 · free 34 · pro 34
LLMs already speak SQL. Give them an engine that reads everything.
PART 2 · THE SECRET

The power is ClickHouse you never noticed

Most people meet ClickHouse as a fast server. Inside, it's also the widest data reader I know.

112
data formats (76 read · 97 write)
system.formats
81
table functions = data sources
system.table_functions
1,874
SQL functions (258 aggregate)
system.functions
Counted from the engine, not the brochure. chdb 4.4 · engine 26.9
PART 2 · SOURCES

One function per place data lives

file()

local · globs · archives

s3() url() gcs()

buckets & HTTP

postgresql()

mysql · mongodb · sqlite · redis

iceberg()

hudi · paimon · lakes
SELECT type, round(avg(price)) AS avg_price FROM s3('https://…/house_0.parquet') GROUP BY type ORDER BY avg_price DESC -- detached 286,753 · flat 198,888 · terraced 157,110
2.77M rows of UK
house sales, queried
where they sit.
No load step. The table is wherever the data already is.
PART 2 · TRICKS

Three tricks most users never see

SCHEMA ON READ

Point at a file. Columns and types are inferred.
DESCRIBE url('…parquet') -- price Int64 -- town String …

GLOBS

A thousand files, one table.
file('logs/2026-*/ *.csv.gz') -- gzip read on the fly

INSIDE ARCHIVES

Query CSVs inside a tar. No unpacking.
file('crm.tar :: users_*.csv') -- 100 rows, 2 files
The messy folder is the database.
LIVE DEMO

Query a file on S3 — from this tab

   ┌────rows─┐
1. │ 2772030 │ -- 2.77 million
   └─────────┘
recorded725 ms · Parquet footer only · laptop Chrome, 2026-10-26
Try next: DESCRIBE url('…') — schema inferred over the internet in ~12 ms after the first read
engine: idle
LIVE DEMO

Convert anything to anything

| rep | region | deals |
|:-|:-|-:|
| Ada | APAC | 12 |
| Lin | EMEA | 7 |
| Sam | APAC | 9 |
recorded10 ms · laptop Chrome, 2026-10-26
Swap the last word:
FORMAT CSV
FORMAT Pretty
FORMAT JSON
FORMAT XML
FORMAT TSKV …

In Python, add INTO OUTFILE 'x.parquet' and you have a file converter.

engine: idle
PART 2 · PUT TOGETHER

One query, three worlds

PROCESS RAM

Python(tickets)

ARCHIVE

crm_exports.tar :: *.csv

CLOUD

url('…/orders.parquet')
SELECT name, tier, subject, sum(amount) AS spendFROM Python(tickets)JOIN file('crm_exports.tar :: users_*.csv') USING …JOIN url('https://auxten.com/…/orders.parquet') USING …GROUP BY name, tier, subject ORDER BY spend DESC
No warehouse.
No load step.
The pipeline is the query.
→ user_58 · pro · api limits · 3,716  (real output)
PART 3 · WHAT WE ADDED

Part 3: what we built on top

ADDED · MINIMAL COPY

DataFrames in and out — no detours

v1
2023
DataFrame→Parquet→engine→Parquet→DataFrame 4 conversions
v2
2024
DataFrame═ pointer ═engine→Parquet→DataFrame input 87× faster
v4
2026
DataFrame═ pointer ═engine═ shared buffers ═DataFrame

Numbers are read where NumPy keeps them. Strings still need encoding — so "minimal copy", not "zero copy" everywhere.

Three versions to remove every serialization step we could.
ADDED · MINIMAL COPY

What fewer copies buys you

10 everyday pandas tasks on 50M rows: chDB vs pandas

4.2×
faster (geometric mean)
won 10 of 10
2.9×
less peak memory (geomean)
won 10 of 10
10.5 → 1.8 GB
peak RAM on a 50M × 10K JOIN
— fits an 8 GB laptop

AWS c6a.4xlarge (16 vCPU, 32 GB) · Python 3.14 · best of 3 · ClickHouse 26.3 webinar benchmark

The same laptop finishes jobs it used to crash on.
ADDED · WEBASSEMBLY

ClickHouse in a browser tab

import { AsyncChdb } from 'chdb-wasm'; const db = await AsyncChdb.create({ moduleUrl, wasmUrl }); await db.registerFile('sales.csv', fileFromInput); const r = await db.query( "SELECT count() FROM file('sales.csv')");
Runs in a Web Worker — the page never freezes
Local files read lazily — never uploaded
Same SQL as the server
~29 MB download, cached after the first visit
Chrome 133+ or recent Firefox
npm i chdb-wasm (v0.4.0) · playground: wasm.chdb.io
Analytics apps with no backend to run — and no data leaving the laptop.
LIVE DEMO

Drop a file on this slide

⬇ drop CSV /
Parquet / JSON
read in this tab · not uploaded
countryordersrevenue
drop a file or load the sample, then Run
waitingno file yet
engine: idle
ADDED · PANDAS API

Change one import

# import pandas as pdimport chdb.datastore as pd orders = pd.read_parquet("orders.parquet") big = orders[orders.amount > 100] top = (big.groupby("country").amount.sum() .sort_values(ascending=False).head(3)) print(top) # runs here — as one ClickHouse query
Same pandas code.
ClickHouse engine
underneath.

Result checked against real pandas, same file · datastore 4.4.0

Millions of people already write pandas. They don't have to learn SQL first.
ADDED · PANDAS API

A compiler, not a wrapper

1 · RECORD

Each pandas call is recorded, not run
filter → groupby → sum → sort → head
→

2 · COMPILE

The chain becomes one SQL query
SELECT … GROUP BY … ORDER BY … LIMIT 3
→

3 · RUN

ClickHouse runs it on all cores
no SQL equivalent? → real pandas for that step
Triggers: print(), len(), .columns, iteration — the moment you actually need the answer.
ADDED · PANDAS API

Same API, different machine underneath

CLICKBENCH · DATAFRAME CATEGORY · 43.77 GIB
relative time, lower is better (1× = fastest possible)
chDB
×1.35
DuckDB
×1.40
Polars
×9.99
pandas
×71.18
14 / 16
everyday ops faster than pandas
10M rows, Parquet → answer
39%
of pandas' peak memory (median)

ClickBench public results · own laptop run for PyCon JP 2026 (best of 2, results parity-checked)

Not a faster pandas. ClickHouse wearing pandas' clothes.
ADDED · POSTGRESQL

The ClickHouse engine, inside Postgres

QUERY ANY SOURCE FROM SQL
SELECT * FROM chdb_query($$ SELECT * FROM s3('s3://…/file_1.csv') $$) AS (id int, months int, days int);
LOAD ANY FORMAT WITH COPY
LOAD 'chdb_hook'; COPY times FROM 's3://…/{some,another}_prefix/file_{1..3}.csv';
pg_chdb
github.com/ClickHouse/pg_chdb
PostgreSQL 15+
Extension in ClickHouse Managed Postgres
Postgres users get ClickHouse's readers without leaving psql.
ADDED · POSTGRESQL

Why Postgres people care

ExtensionCompressionFormats
aws_s3noneTSV, CSV, Postgres binary
pg_duckdbgzip, zstd, snappy*CSV, JSON, Parquet
pg_lakegzip, zstd, snappy*CSV, JSON, Parquet
pg_chdbgzip, zstd, lz4, bz2, snappy, brotliTSV, CSV, JSON, BSON, Parquet, Arrow, ORC, Avro, Protobuf, MsgPack, XML, Prometheus … and more

* snappy for Parquet only · source: pg_chdb docs on clickhouse.com

In ClickHouse's own import benchmark (NYC Taxi, ~1M rows), pg_duckdb and pg_lake
took roughly 2–3× as long as pg_chdb for CSV, JSON and Parquet.
ADDED · EVERYWHERE

Not just Python: 11 ways in

Python
C/C++libchdb
Node.js
Go
Rust
Java
Ruby
.NET
Bun
Zig
WASMbrowser
+ PGpg_chdb

Python and C/C++ are the most mature; Java, .NET, Zig and WASM are early. Same engine under all of them.

Wherever the developer is, ClickHouse can be a dependency.
PART 4 · FOR THE BUSINESS

chDB is the on-ramp, not the replacement

CHDB · INSIDE ONE PROCESS

notebooks · scripts · CI
inside apps & agents
files where they already are
browser & Postgres

CLICKHOUSE SERVER / CLOUD

many users at once
always-on dashboards & APIs
continuous ingestion
data bigger than one machine
Same SQL on both sides →
PART 4 · FOR THE BUSINESS

Three lines for customer conversations

01 "ClickHouse in a pip install." → data scientists, CI, app developers
02 "Query files where they already are." → teams with S3 / Parquet / exports
03 "Same SQL from laptop to Cloud." → anyone worried about lock-in or rewrites
Lead with the pain they have. chDB is the shortest path to "it works".
HONESTY

What not to promise

Not a shared server. One engine per process; for many users, use a server or Cloud.
Remote data is network-bound. A first scan of a big S3 file takes seconds to a minute.
Browser build is young. ~29 MB download, modern browsers only, remote files fetched whole.
pg_chdb is new. Each chdb_query() call is isolated.
Pandas API isn't 100% pandas. Uncovered steps fall back to pandas — correct, not always faster.
Under-promise. The demo does the convincing.
TRY IT

Try it in 30 seconds

# Python pip install chdb # Node.js · browser npm i chdb · npm i chdb-wasm # no install at all open https://wasm.chdb.io # Postgres github.com/ClickHouse/pg_chdb
QR code to these slides

these slides, live engine included

github.com/chdb-io/chdb

Ideas, customer asks, rough edges — bring them to me.

Thank you.

Questions?
chDB

@auxten · auxten.com · github.com/chdb-io/chdb

What is chDB, and what can you use it for?2026-10-28