mcpbeat

Clickhouse Js Node Rowbinary

clickhouse/clickhouse-js-node-rowbinary

> Generate TypeScript/JavaScript code that reads/decodes AND writes/encodes ClickHouse RowBinary streams for the ClickHouse HTTP server. Use this skill whenever a user wants to parse or produce `RowBinary`, `RowBinaryWithNames`, or `RowBinaryWithNamesAndTypes`. Node.js only, doesn't cover browsers.

174k tokens
context cost
the whole folder, loaded on every use
193
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
35 d ago
last touched
this folder, not the whole repository

Install

one command, takes just this skill from the repository
npx skills add https://github.com/ClickHouse/agent-skills --skill clickhouse-js-node-rowbinary

What comes with it

236 369 bytes besides the instruction
.gitignore
AGENTS.md
CHANGELOG.md
EXAMPLES.md
README.md
case-studies/iot-rowbinary-vs-json.md
case-studies/ledger-rowbinary-vs-json.md
case-studies/logs-json-wins.md
case-studies/wasm-vs-js.md
eval_result.md
eval_result_composer.md
eval_result_haiku.md
eval_result_sonnet.md
package-lock.json
package.json
reader.md
src/examples/carts.ts
src/examples/events.ts
src/examples/iot.ts
src/examples/ledger.ts
src/examples/logs.ts
src/examples/observability.ts
src/examples/orders.ts
src/examples/profiles.ts
src/examples/telemetry.ts
src/readers/aggregateFunction.ts
src/readers/bool.ts
src/readers/columnar.ts
src/readers/compile.ts
src/readers/composite.ts
src/readers/core.ts
src/readers/datetime.ts
src/readers/decimals.ts
src/readers/dynamic.ts
src/readers/enums.ts
src/readers/floats.ts
src/readers/geo.ts
src/readers/header.ts
src/readers/integers.ts
src/readers/interval.ts

The instruction itself

6 sections, as written by the author

ClickHouse JS RowBinary Codec Generator for Node.js

This skill generates both directions of the wire format: readers (decode

bytes → values) and writers (encode values → bytes, the mirror). A given

task normally needs only one side. This file is the shared entry point — the

format gate plus the principles common to both directions; the per-direction

decisions, guidance, and the per-type reference tables live in two sibling files.

Pick your side — read only the one you need:

  • Decoding a RowBinary* response from ClickHouse into JS values →

reader.md. Streaming vs whole-buffer, row-objects vs columnar,

fixed vs runtime schema, and the per-type reader reference.

  • Encoding JS values into a RowBinary payload to send to ClickHouse →

writer.md. The Sink/writeX building blocks, writeRows

streaming, and the per-type writer reference.

The per-type code is real, split by direction under src/readers/ and

src/writers/.

First: is RowBinary even the right format?

RowBinary exists for throughput, but it is **not automatically the fastest

path** — match the format to the shape of the data before committing to a

bespoke parser.

Prefer a JSON* format (e.g. JSONEachRow) when the result is mostly

strings / JSON-like values that you consume wholesale — randomly accessing

essentially every field, running string/regexp methods on them, treating values

as text. V8's native JSON.parse is heavily optimized C++ and builds JS strings

and objects faster than a JS-level RowBinary decoder can; pair it with HTTP

response compression (gzip / zstd, which crushes JSON's repetitive keys) and

the wire cost shrinks too.

RowBinary clearly wins when the result is dominated by:

  • Wide numericsInt128/Int256/UInt128/UInt256,

Decimal128/Decimal256.

  • Binary / fixed-width blobsIPv4, IPv6, UUID, FixedString.
  • High-volume fixed-width numeric columns generally, where each value is a

single DataView read.

Prefer the Native format when columnar load and client-side analytics are

the main goal (fold/scan/filter columns, feed typed arrays to a Worker or WASM).

Native is column-major, so it loads straight into one typed array per column

with no transpose.

For help choosing and consuming a JSON* format (or CSV / TSV) instead, use the

clickhouse-js-node-coding skill.

Core guidance (both directions)

These principles apply whether you are generating a reader or a writer; the

side-specific operational guidance is in reader.md /

writer.md.

  • Little-endian only. RowBinary is little-endian; target x86/ARM. Read and

write every multi-byte number with DataView accessors passing a literal

true for the littleEndian flag.

  • Correct first, then optimize. First emit a correct codec built from the

plain per-type API. Only after it's correct (and tested) specialize it. Don't

bake performance assumptions in before correctness.

  • Monomorphize generic/composite types. Emit specialized, inlined code per

type combination instead of passing functions as arguments where the type is

known ahead of time.

  • Inline the leaf ops. The per-type readX/writeX functions are the

correct, composable reference; the generated codec should INLINE their bodies,

not call them, so the row loop is straight-line with no per-field indirection

(and so the fixed-width coalescing can fold the offset arithmetic together).

  • Annotate the type per column. Inlining erases the type structure, so put a

short comment above each column's encode/decode block naming the ClickHouse

type it handles.

  • Shared scratch is not reentrant. Some hot methods reuse a module-level

scratch buffer as a write-then-read pair — correct only because the access is

fully synchronous. An async/yield boundary between populating and reading

it corrupts the value.

  • TypeScript by default. Generate TypeScript code and helpers unless the user

explicitly asks for plain JavaScript.

Worked examples

Six end-to-end examples with real speedup are catalogued in EXAMPLES.md.

Out of scope

  • JSON / CSV / TSV / Parquet parsing → use clickhouse-js-node-coding.
  • Connection errors, hangs, type mismatches → use

clickhouse-js-node-troubleshooting.

  • Browser / Web Worker / Edge@clickhouse/client-web.

Still Stuck?

How to use it

Copy the folder

Take clickhouse/clickhouse-js-node-rowbinary from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.