ClickHouse Node.js

Use ClickHouse from Node.js without hand-maintained query types

This page is narrower than the JavaScript page. It is about the backend reality: scripts, workers, Express servers, and the point where a query needs to become a reusable API instead of another helper buried in a service file.

Runtime

Node.js and Bun

Frameworks

Express, Next.js, custom Node servers

Type source

Generated from schema

Node services accumulate query helpers fast

A server codebase rarely has just one query caller. Jobs, workers, route handlers, and admin tasks all want the same data, and each one tends to grow its own helper if there is no shared path.

The HTTP layer keeps getting rebuilt

Once a query needs an endpoint, teams start writing validation, auth handling, error shaping, and docs around it. That is a lot of repeated backend work for what should still be one analytics query.

Type mismatches hide inside server code

Node developers often spot the runtime mismatch later because the wrong shape is hidden inside service code and only surfaces after it has already passed through several layers.

Setup

Start with a typed backend query layer, not another helper module

Generate the schema once, initialize the builder in your backend, and make that the standard way Node code reaches ClickHouse. That gives scripts, workers, and services the same typed starting point.

  • Works well in Node.js services, scripts, and Bun runtimes
  • Schema types generated from your live ClickHouse instance
  • Correct ClickHouse-to-Node.js type mappings — no guessing
  • Composable query builder with support for typed filters, joins, CTEs, and raw SQL when needed
  • Optional HTTP serving layer via @hypequery/serve handlers

Setup

A backend entry point you can reuse across services and jobs

setup.ts

The point of this setup is consistency. Once the builder exists in one standard place, the rest of the Node codebase stops reinventing how it talks to ClickHouse.

With Express

Promote a query into an endpoint without burying logic in the route

When Node code needs to expose analytics over HTTP, keep the query definition separate from the web framework and mount the handler around it. That keeps the route thin and the analytics logic reusable.

That separation is what makes the Node page distinct from the framework pages. The query can still run directly inside a job or script, and only becomes an HTTP concern when you actually need a server surface.

If your app is specifically App Router-first, use the Next.js page. This page is for the general backend case where Express-style or standalone Node runtimes are still the center of gravity.

Express integration

A thin Express mount around a shared analytics definition

with-express.ts

The useful part is not the middleware line by itself. It is that the route is no longer where the analytics logic lives.

Where teams usually get stuck

The questions this page should answer

What this page is really for

It is for backend teams whose main concern is service code, jobs, and server routes, not client hooks or App Router rendering.

Where Node teams usually feel pain

Usually when the same query appears in a worker, a route, and a report generator and every copy evolves separately.

Why the server layer matters

Backend teams end up paying for every decision twice if query logic and route logic are fused together. This page is about keeping them separate.

Where to branch next

Use the Next.js page for App Router specifics and the REST page if the endpoint layer itself is your main concern.

Next step

Replace one backend query path end to end

Pick one script, worker, or route that currently owns its own ClickHouse query code, move it onto the shared builder, and then decide whether it also deserves a served API surface.