ClickHouse JS

The JavaScript query builder built for ClickHouse

This page is for teams starting from plain JavaScript or TypeScript and wondering how far the raw ClickHouse client really gets them. hypequery keeps the connection layer, but adds schema-driven query code so the rest of the app is not built on casts and copied SQL.

Language

JavaScript & TypeScript

Type source

Generated from schema

Best for

Analytics-heavy JS apps

The raw client stops at query execution

It connects to ClickHouse and runs SQL well. The problem starts after that, when every caller has to decide what the rows look like and how much parsing or casting it wants to do.

JavaScript callers keep re-solving the same runtime type issues

DateTime, UInt64, Nullable, and Decimal do not map the way many teams expect. Without a shared type source, every query callsite ends up making its own assumptions.

The same query logic leaks into every runtime

A JavaScript stack often spans scripts, server code, and UI consumers. If the query only exists as a string plus an informal row shape, reuse turns into copy-paste very quickly.

What changes

Keep the JavaScript runtime, replace the fragile query layer

The useful move is not adopting a whole new stack. It is generating a schema file from ClickHouse and using that as the basis for query code, so JavaScript callers stop inventing row types ad hoc.

  • Schema types generated from your live ClickHouse database
  • Correct JS runtime type mappings — DateTime→string, UInt64→string, Nullable→T|null
  • Composable builder with filters, groupBy, orderBy, and aggregations
  • Composable builder plus raw SQL escape hatches for ClickHouse-specific clauses
  • Works across Node.js, Next.js, Bun, and other JavaScript runtimes

Before vs after

From raw client rows to schema-aware query results

what-changes.ts

The important difference is not style. It is that the second version has a real type source instead of leaving every caller to cast the result however it likes.

When a query becomes shared

Move useful queries into named definitions

Once a JavaScript query stops being local implementation detail, it should stop living as an unstructured string. Promote it into a named definition and let the rest of the stack consume that definition instead.

That is the practical difference between this page and the raw-client story. The client gives you transport. The named query layer gives you something the rest of the product can safely call.

If you are evaluating the tradeoffs, the comparison page spells out where @clickhouse/client stays the simpler option and where it starts leaving too much work to application code.

Named query

A reusable query definition instead of another raw string

when-a-query-becomes-shared.ts

This is the step that makes the JavaScript story scale. The query stops being “whatever this file does” and becomes something the rest of the app can depend on.

Where teams usually get stuck

The questions this page should answer

What this page is really comparing

It is less about official client versus unofficial client, and more about whether query code stays raw and local or becomes typed and reusable.

Where JavaScript teams usually get stuck

Usually not on connecting to ClickHouse. Usually on keeping row shapes, response parsing, and copied SQL under control once the codebase grows a few consumers.

Why the type source matters

If the query layer starts from the wrong assumptions about DateTime or UInt64, every higher-level abstraction inherits the mistake.

Where to branch next

Use the Node.js page for server and job concerns, Next.js for App Router concerns, and React for browser consumption.

Next step

Replace one raw query in a JavaScript runtime you already own

Pick a query that currently returns untyped rows, generate the schema, and move that query onto the builder. That is enough to see whether the workflow earns its place.