← Files ClickHouseARCHIVED FILE

skills/clickhouse-js-node-coding/reference/insert-formats.md

6.15 KB · Sep 30, 2026 · 22:50 UTC

↓ Download file

# Insert Data Formats

> **Applies to:** all versions. The `JSON` type column / new JSON family is a
> ClickHouse feature; the JSON _formats_ listed here are universally supported
> by the client.

> **Raw / binary formats (CSV, TSV, CustomSeparated, Parquet) require a Node
> stream as input.** Suggest streaming when the user wants to insert from a file or `Readable`.

## Answer checklist

When answering "what format/call should I use for an array of JS objects?":

- Use `client.insert({ table, values, format: 'JSONEachRow' })`.
- Say the array of plain objects can be passed directly as `values` for
  ordinary in-memory batches such as a few thousand or tens of thousands of
  rows.
- Do not steer the user to streaming, Parquet, or file APIs unless their input
  is already a stream/file or the task is explicitly about throughput.
- Warn not to wrap `JSONEachRow` rows in a `{ data: [...] }` envelope; that
  shape belongs to single-document formats.
- Mention `JSONCompactEachRow*` as a denser alternative for larger payloads
  when the caller can provide positional arrays or explicit names/types.

## Default choice: `JSONEachRow` with an array of objects

This is the right answer for ~90% of inserts.

```ts
import { createClient } from "@clickhouse/client";

const client = createClient();

await client.insert({
  table: "events",
  format: "JSONEachRow",
  values: [
    { id: 42, name: "foo" },
    { id: 43, name: "bar" },
  ],
});

await client.close();
```

The shape of `values` must match the chosen format.

## Streamable JSON formats (pass an array)

| Format                                       | `values` shape                                      |
| -------------------------------------------- | --------------------------------------------------- |
| `JSONEachRow`                                | `Array<{ col: value, ... }>`                        |
| `JSONStringsEachRow`                         | `Array<{ col: stringifiedValue, ... }>`             |
| `JSONCompactEachRow`                         | `Array<[v1, v2, ...]>`                              |
| `JSONCompactStringsEachRow`                  | `Array<[stringV1, stringV2, ...]>`                  |
| `JSONCompactEachRowWithNames`                | First row = column names, then data rows            |
| `JSONCompactEachRowWithNamesAndTypes`        | Row 1 = names, row 2 = types, then data             |
| `JSONCompactStringsEachRowWithNames`         | First row = names, then stringified data rows       |
| `JSONCompactStringsEachRowWithNamesAndTypes` | Row 1 = names, row 2 = types, then stringified data |

```ts
await client.insert({
  table: "events",
  format: "JSONCompactEachRowWithNamesAndTypes",
  values: [
    ["id", "name", "sku"],
    ["UInt32", "String", "Array(UInt32)"],
    [11, "foo", [1, 2, 3]],
    [12, "bar", [4, 5, 6]],
  ],
});
```

These formats can be **streamed** — pass a Node stream of rows instead of an
array. See
[`examples/node/performance/`](https://github.com/ClickHouse/clickhouse-js/tree/main/examples/node/performance)
for streaming guidance.

## Single-document JSON formats (pass an object)

These cannot be streamed — the entire body is sent in one shot.

| Format                    | `values` shape (typed via `InputJSON<T>` / `InputJSONObjectEachRow<T>`)                                                   |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `JSON`                    | `{ meta: [], data: Array<{ col: value, ... }> }` — for TypeScript/client usage, pass `meta: []` if metadata is not needed |
| `JSONCompact`             | `{ meta: [{ name, type }, ...], data: Array<[v1, v2, ...]> }`                                                             |
| `JSONColumnsWithMetadata` | `{ meta: [...], data: { col1: [v, ...], col2: [v, ...] } }`                                                               |
| `JSONObjectEachRow`       | `Record<string, { col: value, ... }>` (the record key labels each row but is not stored)                                  |

```ts
import type { InputJSON, InputJSONObjectEachRow } from "@clickhouse/client";

const meta: InputJSON["meta"] = [
  { name: "id", type: "UInt32" },
  { name: "name", type: "String" },
];

await client.insert({
  table: "events",
  format: "JSONCompact",
  values: {
    meta,
    data: [
      [19, "foo"],
      [20, "bar"],
    ],
  },
});

await client.insert({
  table: "events",
  format: "JSONObjectEachRow",
  values: {
    row_1: { id: 23, name: "foo" },
    row_2: { id: 24, name: "bar" },
  } satisfies InputJSONObjectEachRow<{ id: number; name: string }>,
});
```

## Quick chooser

| Use case                                     | Format                                                  |
| -------------------------------------------- | ------------------------------------------------------- |
| Insert plain JS objects                      | `JSONEachRow` _(default)_                               |
| Insert tuples / column-positional rows       | `JSONCompactEachRow`                                    |
| Insert with explicit column ordering / types | `JSONCompactEachRow*WithNames…`                         |
| Insert a single document with metadata       | `JSON`, `JSONCompact`                                   |
| Insert from a CSV / TSV / Parquet file       | Raw format + Node stream → `examples/node/performance/` |

## Common pitfalls

- **Wrong shape for the format.** The most common cause of insert failures —
  e.g., passing `Array<{...}>` to `JSONCompact` (which expects
  `{ meta, data }`).
- **Don't wrap a `JSONEachRow` array in a `{ data: [...] }` envelope.** That
  envelope only belongs to single-document formats (`JSON` / `JSONCompact` /
  `JSONColumnsWithMetadata`).
- For type guidance (`Decimal` strings, `Date` objects, `BigInt`), see
  `insert-values.md` and `custom-json.md`.
- **Use runtime type checkers like `zod` or `io-ts` if your app ingests untrusted JSON.**
  It's easier to debug mismatches between your data and the format's expected shape with a validation library used at the place of ingestion than with ClickHouse errors, especially in the middle of a large insert batch or streaming operation.

SHA-256: 3cff7ffb2cb226d5e048b70f4597825a5f3e4d30dfc0daef7277f507efb47ddf