← Files ClickHouseARCHIVED FILE

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

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

↓ Download file

# Async Inserts

> **Applies to:** all client versions; the relevant settings are server-side.
> See https://clickhouse.com/docs/en/optimize/asynchronous-inserts.

> **When to use async inserts:** when many small inserts arrive concurrently
> (e.g., one per HTTP request) and you don't want to maintain a client-side
> batching layer. ClickHouse will batch them server-side. This is also the
> recommended ingestion pattern for **ClickHouse Cloud**.

> **When _not_ to use async inserts:** when you already build large batches
> client-side (e.g., from a stream). Plain inserts are simpler and lower
> latency.

## Setup

Enable on the client level or per-request via `clickhouse_settings`:

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

const client = createClient({
  url: process.env.CLICKHOUSE_URL,
  password: process.env.CLICKHOUSE_PASSWORD,
  max_open_connections: 10,
  clickhouse_settings: {
    async_insert: 1,
    wait_for_async_insert: 1, // wait for ack from server
    async_insert_max_data_size: "1000000",
    async_insert_busy_timeout_ms: 1000,
  },
});
```

## Concurrent small inserts

Each call still uses the client's normal `insert()` API — the server merges
the batches.

```ts
const promises = [...new Array(10)].map(async () => {
  const values = [...new Array(1000).keys()].map(() => ({
    id: Math.floor(Math.random() * 100_000) + 1,
    data: Math.random().toString(36).slice(2),
  }));

  await client
    .insert({ table: "async_insert_example", values, format: "JSONEachRow" })
    .catch((err) => {
      if (err instanceof ClickHouseError) {
        // err.code matches a row in system.errors
        console.error(`ClickHouse error ${err.code}:`, err);
        return;
      }
      console.error("Insert failed:", err);
    });
});

await Promise.all(promises);
```

## `wait_for_async_insert` — fire-and-forget vs ack

| `wait_for_async_insert` | Promise resolves when…                            | Trade-off                                                           |
| ----------------------- | ------------------------------------------------- | ------------------------------------------------------------------- |
| `1` (default)           | Server has flushed the batch to the table         | Slower per call; insert errors surface to the client                |
| `0`                     | Server accepted the row into its in-memory buffer | Faster; flush errors won't surface — only validation/parsing errors |

With `wait_for_async_insert: 1`, expect each insert call to take roughly
`async_insert_busy_timeout_ms` to resolve when traffic is light, because the
server waits for more rows or for the timer to fire before flushing.

## Combining DDL with async inserts

When creating tables in scripts that immediately insert, ack the DDL with
`wait_end_of_query: 1` so the table is ready before the first insert:

```ts
await client.command({
  query: `
    CREATE OR REPLACE TABLE async_insert_example (id Int32, data String)
    ENGINE MergeTree ORDER BY id
  `,
  clickhouse_settings: { wait_end_of_query: 1 },
});
```

Even better is to create a specialized client for inserts with the appropriate async
settings and a separate client for DDL and other queries.

## Common pitfalls

- **Setting `async_insert` per call but expecting client-side batching.**
  The client still issues each `insert()` as a separate HTTP request — the
  batching happens on the server.
- **Confusing `wait_for_async_insert` (async-insert ack) with
  `wait_end_of_query` (DDL ack).** They are unrelated.
- **Treating a resolved insert under `wait_for_async_insert: 0` as
  durably written.** It only means the server accepted the bytes; flush
  failures will not surface to the client.
- **Not handling `ClickHouseError`.** It exposes `err.code`, which maps to
  rows in the `system.errors` table — use it to decide whether to retry.

## See also

- For raw throughput tuning of large async-insert workloads,
  see [`examples/node/performance/`](https://github.com/ClickHouse/clickhouse-js/tree/main/examples/node/performance).

SHA-256: 21d66ab2e8d085d2a337c326ea1dc36c639904b4b5b62a75f168df3c0e698938