chtypeGitHub
Open Source

Type-safe ClickHouse
for TypeScript

Generate types from your schema. Build queries with full autocomplete and compile-time validation. Catch errors before they hit production.

$npm install @jantokic/chtype
query.ts
// chtype — every mistake caught at compile time
const result = await db
.selectFrom("events")
.select(["user_id", fn.count()])// ← autocomplete
.where("event_type", "=", "purchase")// ← parameterized
.groupBy(["user_id"])
.orderBy(fn.count(), "DESC")
.limit(10)
.execute();
// result: { user_id: string; count: number }[]
// type-safe autocomplete injection-proof

Using raw @clickhouse/client?

No type safety — column names are plain strings. Typo in a column name? You won't know until runtime. In production. At 3am.

No autocomplete — your IDE can't help you. Every query is a black box of string concatenation. Want to know what columns exist? Go check the ClickHouse console.

No schema codegen — every time you add a column, you manually update TypeScript interfaces. They drift apart. Nobody notices until the wrong data flows through.

No ClickHouse features — Kysely doesn't know about FINAL, argMax, SETTINGS, or ReplacingMergeTree. Prisma and Drizzle don't even support ClickHouse.

chtype generates types directly from your ClickHouse schema, then gives you a query builder that catches every mistake at compile time.

Codegen

Types from your actual schema.

Run one command and get TypeScript types for every table. Row types for reads, Insert types for writes — with DEFAULT columns optional and MATERIALIZED columns excluded automatically.

Schema Codegennpx chtype generate
// Generated from ClickHouse
export type EventsRow = {
id: string;
timestamp: Date;
user_id: string;
event_type: string;
properties: string;
};
export type EventsInsert = {
id?: string; // DEFAULT
timestamp: Date;
// ...
};
Query Builder

Autocomplete everything.

Column names, operators, sort directions — all validated at compile time. Typo a column name? TypeScript catches it before you even save the file. No more runtime surprises.

Full Autocompletecompile-time checked
const query = db
.selectFrom("events")
.select(["id", "user_id", "timestamp"])
.where("user_id", "=", userId)
.orderBy("timestamp", "DESC")
.limit(100);
// Error: "usre_id" not in Events
// Autocomplete: id | user_id | ...
ClickHouse-Native

Built for ClickHouse, not bolted on.

argMax for ReplacingMergeTree deduplication, FINAL modifier, query-level SETTINGS, engine-aware types. Features that generic query builders like Kysely or Drizzle simply can't offer.

ClickHouse-Nativenot a generic ORM
// Deduplicate ReplacingMergeTree
db.selectFrom("users")
.select(["id", "name", "email"])
.argMax() // auto version column
.groupBy(["id"])
// FINAL modifier for debug
db.selectFrom("users", { final: true })
// Query-level SETTINGS
.settings({ max_threads: 4 })
Lightweight

Zero overhead. Full power.

chtype compiles down to plain parameterized SQL. No ORM magic, no runtime reflection, no query overhead. Just type-safe queries that run exactly as fast as hand-written SQL.

Zero Runtime Overheadcompiles to plain SQL
+
Parameterized queries
SQL injection impossible by design
+
Row vs Insert types
DEFAULT columns optional, MATERIALIZED excluded
+
Engine metadata
ReplacingMergeTree version column tracking
+
CTE support
WITH clauses with column type inference
+
Escape hatches
fn.raw() for anything non-standard
See it in action

From schema to type-safe query

One command generates your types. Then your IDE does the rest.

chtype
// Full autocomplete on every method
const result = await db
.selectFrom("events")
.select(["user_id", fn.count()])
.where("event_type", "=", "purchase")
.groupBy(["user_id"])
.orderBy(fn.count(), "DESC")
.limit(10)
.execute();
// result type: { user_id: string; count: number }[]
// Parameterized: no SQL injection possible

Stop writing ClickHouse queries in the dark.

Type safety, autocomplete, and codegen. All in one lightweight package.

$npm install @jantokic/chtype