ClickHouse tRPC

Use hypequery ClickHouse queries as tRPC procedures

tRPC gives you end-to-end type safety from server to React client. hypequery gives you end-to-end type safety from ClickHouse schema to TypeScript. Combining them means your analytics procedures are typed all the way from the database column definition to the component that renders the chart.

Integration layer

tRPC procedure

Type source

ClickHouse schema

Best for

Full-stack TypeScript apps

tRPC doesn't query ClickHouse natively — you lose types immediately

tRPC procedures delegate to whatever data layer you choose. When that layer is raw @clickhouse/client, the response is untyped. You end up casting to any or manually annotating shapes that should be inferred from the ClickHouse schema itself.

ClickHouse analytics need a bridge into the tRPC router model

A tRPC procedure expects validated input and a typed return value. ClickHouse queries produce rows with column names and ClickHouse-native types — DateTime, UInt64, Nullable. Reconciling the two by hand means schema definitions in three places: the database, the query, and the tRPC output type.

Multi-tenant analytics need tenant context from tRPC ctx — wiring it manually is repetitive

Every analytics procedure needs to read tenantId from the tRPC context and inject it into the ClickHouse WHERE clause. Without a shared pattern, each procedure implements its own auth extraction and tenant filtering independently.

How it fits together

Call hypequery inside tRPC procedures — types flow through automatically

hypequery query builder methods return TypeScript types inferred directly from your ClickHouse schema. When you call those methods inside a tRPC procedure, the return type of the procedure is inferred automatically — no manual annotation, no casting.

  • Run npx @hypequery/cli generate to produce schema.ts from your live ClickHouse instance
  • Import db (the typed query builder) and call it inside a tRPC procedure
  • Pass ctx.tenantId from tRPC context directly into the WHERE clause
  • tRPC infers the procedure output type from the hypequery return value
  • useQuery() on the client gets the same inferred type — DateTime columns as string, UInt64 as string, Nullable as T | null

tRPC procedure

Typed ClickHouse query inside a tRPC router

how-it-fits-together.ts

Tenant context flows from tRPC ctx to the ClickHouse WHERE clause. The procedure output type is inferred from the query — no manual annotation needed.

Full stack

From ClickHouse schema to React hook — one type chain, no casting

The hypequery query builder produces column types from your schema. Those types become the tRPC procedure output. tRPC propagates them to the React client. The component that renders the chart knows the exact shape of every row without any manual type annotation in the middle.

This pattern scales to multi-tenant apps cleanly. Each procedure reads tenantId from the tRPC context once — defined in the context factory when you create the tRPC instance — and passes it to the ClickHouse query. No per-procedure auth logic.

If you need HTTP access from outside the tRPC client (mobile apps, third-party consumers), pair this with @hypequery/serve to expose the same query as a REST endpoint alongside the tRPC router.

Full stack example

tRPC procedure and the React hook that consumes it

full-stack.ts

The component does not import any ClickHouse types. Everything is inferred through tRPC from the hypequery query definition.

Where teams usually get stuck

Questions teams ask

ClickHouse tRPC router

Adding ClickHouse queries to a tRPC router is straightforward: call the hypequery query builder inside your procedure and return the result. tRPC infers the output type from whatever the async function returns.

tRPC analytics backend TypeScript

A tRPC analytics backend needs validated inputs, typed ClickHouse responses, and tenant context injection. hypequery handles the ClickHouse side — you wire the tRPC context once and every procedure inherits it.

ClickHouse typed procedures

ClickHouse column types (DateTime, UInt64, Nullable) map to TypeScript types through hypequery schema generation. The procedure output type is inferred — you never write a manual response interface for a ClickHouse query again.

tRPC ClickHouse query builder

Using a query builder inside tRPC procedures keeps analytics logic reusable. The same hypequery query can run inside a tRPC procedure, a server component, or a cron job — it's not bound to the HTTP layer.

Next step

Generate your schema, then call the query builder inside a tRPC procedure

Run npx @hypequery/cli generate to produce typed schema bindings from your ClickHouse instance. After that, the query builder is ready to call from any tRPC procedure — types flow through automatically.