ClickHouse Python
Use ClickHouse from Python with a semantic layer, not just a driver
A driver gets rows out of ClickHouse. hypequery gives your Python code shared definitions on top: measures, dimensions, relationships, and tenant rules you define once and query by name from jobs, notebooks, and FastAPI services.
Python
3.11+
Execution
Sync and async ClickHouse
Serving
FastAPI router
Every service rewrites the same SQL
Revenue, active users, and churn end up as string templates copied across jobs, notebooks, and API handlers. Each copy drifts, and nobody is sure which one is right.
Tenant filters depend on remembering them
In a multi-tenant product, every query needs a tenant predicate. With raw SQL that is a convention, and one forgotten WHERE clause is a data leak.
Drivers stop at rows
A ClickHouse driver connects and returns results. It does not know what revenue means, which fields callers may group by, or how to cache an answer safely per tenant.
Define
Model a table once as a dataset
A dataset maps a ClickHouse table to named dimensions and measures. It is plain Python, so it lives in your repository, goes through code review, and is tested in CI like the rest of your application.
- Dimensions, measures, filtered measures, and relationships
- Tenant and time keys declared on the dataset, enforced on every query
- Validated when you define it, so typos fail before production
- The same semantic model and artifacts as the TypeScript SDK
Dataset
A ClickHouse table with named measures
Aggregations live on measure (measure.sum, measure.count), so nothing shadows a Python built-in.
Query
Ask for measures by name, and let hypequery write the SQL
Queries select semantic names. hypequery plans parameterized ClickHouse SQL, adds the tenant predicate from a trusted execution context, and returns rows keyed by column name.
Because the tenant comes from the execution context rather than the query, a request body or notebook cell cannot widen its own access. A query without tenant context against a tenant-scoped dataset is rejected outright.
The same client supports result caching with tenant-safe keys, validation without execution, and a redacted SQL preview for debugging.
Execution
A tenant-scoped query against ClickHouse
Execution uses clickhouse-connect underneath. Async code can use the async client and executor instead.
Where teams usually get stuck
Questions teams ask
Who this is for
Python teams that query ClickHouse from more than one place and want shared definitions instead of copied SQL.
How it relates to clickhouse-connect
It builds on the driver rather than replacing it. Keep the driver for ad hoc SQL, and use datasets for analytics that other code depends on.
When to add serving
When a dashboard, customer, or agent needs the same numbers over HTTP. The FastAPI router serves datasets without new query code, and its endpoints feed type-safe React hooks and MCP tools.
TypeScript too
Python and TypeScript share the same specifications and conformance fixtures, so mixed-language teams can share one model. The Python SDK is in beta.
Further reading
Go deeper where it actually helps
FastAPI and React analytics
Typed React hooks on the endpoints your Python app serves.
Open guide
hypequery vs clickhouse-connect
When to keep the driver for ad hoc SQL, and when shared datasets earn their place.
Open guide
ClickHouse FastAPI
Serve Python datasets as authenticated, tenant-scoped HTTP endpoints.
Open guide
Python semantic layer
Why define analytics as Python code instead of YAML or a separate server.
Open guide
Python datasets docs
Dimensions, measures, relationships, caching, and multi-tenancy in Python.
Open guide
Multi-tenant ClickHouse analytics
Patterns for isolating customers in shared ClickHouse tables.
Open guide
Next step
Model one table and replace one query
Pick the ClickHouse query your team copies most often, define it as a dataset, and point one job or endpoint at it.
Open source, and it runs in your own backend. Want it hosted?