Documentation Index
Fetch the complete documentation index at: https://private-7c7dfe99-page-updates.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Streaming files (Node.js only)
There are several file streaming examples with popular data formats (NDJSON, CSV, Parquet) in the client repository.- Streaming from an NDJSON file
- Streaming from a CSV file
- Streaming from a Parquet file
- Streaming into a Parquet file
query call (JSONEachRow, CSV, etc.) and the output file name.
Supported data formats
The client handles data formats as JSON or text. If you specifyformat as one from the JSON family of formats (JSONEachRow, JSONCompactEachRow, etc.), the client will serialize and deserialize data during the communication over the wire.
Data provided in the “raw” text formats (CSV, TabSeparated and CustomSeparated families) are sent over the wire without additional transformations.
| Format | Input (array) | Input (object) | Input/Output (Stream) | Output (JSON) | Output (text) |
|---|---|---|---|---|---|
| JSON | ❌ | ✔️ | ❌ | ✔️ | ✔️ |
| JSONCompact | ❌ | ✔️ | ❌ | ✔️ | ✔️ |
| JSONObjectEachRow | ❌ | ✔️ | ❌ | ✔️ | ✔️ |
| JSONColumnsWithMetadata | ❌ | ✔️ | ❌ | ✔️ | ✔️ |
| JSONStrings | ❌ | ❌️ | ❌ | ✔️ | ✔️ |
| JSONCompactStrings | ❌ | ❌ | ❌ | ✔️ | ✔️ |
| JSONEachRow | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONEachRowWithProgress | ❌️ | ❌ | ✔️ ❗- see below | ✔️ | ✔️ |
| JSONStringsEachRow | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONCompactEachRow | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONCompactStringsEachRow | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONCompactEachRowWithNames | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONCompactEachRowWithNamesAndTypes | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONCompactStringsEachRowWithNames | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| JSONCompactStringsEachRowWithNamesAndTypes | ✔️ | ❌ | ✔️ | ✔️ | ✔️ |
| CSV | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| CSVWithNames | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| CSVWithNamesAndTypes | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| TabSeparated | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| TabSeparatedRaw | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| TabSeparatedWithNames | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| TabSeparatedWithNamesAndTypes | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| CustomSeparated | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| CustomSeparatedWithNames | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| CustomSeparatedWithNamesAndTypes | ❌ | ❌ | ✔️ | ❌ | ✔️ |
| Parquet | ❌ | ❌ | ✔️ | ❌ | ✔️❗- see below |
JSONEachRowWithProgress is an output-only format that supports progress reporting in the stream. See this example for more details.
The entire list of ClickHouse input and output formats is available
here.
Supported ClickHouse data types
The related JS type is relevant for any
JSON* formats except the ones that represent everything as a string (e.g. JSONStringEachRow)| Type | Status | JS type |
|---|---|---|
| UInt8/16/32 | ✔️ | number |
| UInt64/128/256 | ✔️ ❗- see below | string |
| Int8/16/32 | ✔️ | number |
| Int64/128/256 | ✔️ ❗- see below | string |
| Float32/64 | ✔️ | number |
| Decimal | ✔️ ❗- see below | number |
| Boolean | ✔️ | boolean |
| String | ✔️ | string |
| FixedString | ✔️ | string |
| UUID | ✔️ | string |
| Date32/64 | ✔️ | string |
| DateTime32/64 | ✔️ ❗- see below | string |
| Enum | ✔️ | string |
| LowCardinality | ✔️ | string |
| Array(T) | ✔️ | T[] |
| (new) JSON | ✔️ | object |
| Variant(T1, T2…) | ✔️ | T (depends on the variant) |
| Dynamic | ✔️ | T (depends on the variant) |
| Nested | ✔️ | T[] |
| Tuple(T1, T2, …) | ✔️ | [T1, T2, …] |
| Tuple(n1 T1, n2 T2…) | ✔️ | { n1: T1; n2: T2; …} |
| Nullable(T) | ✔️ | JS type for T or null |
| IPv4 | ✔️ | string |
| IPv6 | ✔️ | string |
| Point | ✔️ | [ number, number ] |
| Ring | ✔️ | Array<Point> |
| Polygon | ✔️ | Array<Ring> |
| MultiPolygon | ✔️ | Array<Polygon> |
| Map(K, V) | ✔️ | Record<K, V> |
| Time/Time64 | ✔️ | string |
Date/Date32 types caveats
Since the client inserts values without additional type conversion,Date/Date32 type columns can only be inserted as
strings.
Example: Insert a Date type value.
Source code
DateTime or DateTime64 columns, you can use both strings and JS Date objects. JS Date objects can be passed to insert as-is with date_time_input_format set to best_effort. See this example for more details.
Decimal* types caveats
It is possible to insert Decimals usingJSON* family formats. Assuming we have a table defined as:
JSON* formats, ClickHouse will return Decimals as numbers by default, which could lead to precision loss. To avoid this, you could cast Decimals to string in the query:
Integral types: Int64, Int128, Int256, UInt64, UInt128, UInt256
Though the server can accept it as a number, it is returned as a string inJSON* family output formats to avoid
integer overflow as max values for these types are bigger than Number.MAX_SAFE_INTEGER.
This behavior, however, can be modified
with output_format_json_quote_64bit_integers setting
.
Example: Adjust the JSON output format for 64-bit numbers.
ClickHouse settings
The client can adjust ClickHouse behavior via settings mechanism. The settings can be set on the client instance level so that they will be applied to every request sent to the ClickHouse:Advanced topics
Queries with parameters
You can create a query with parameters and pass values to them from client application. This allows to avoid formatting query with specific dynamic values on client side. Format a query as usual, then place the values that you want to pass from the app parameters to the query in braces in the following format:name— Placeholder identifier.data_type- Data type of the app parameter value.
Compression
NB: request compression is currently not available in the Web version. Response compression works as normal. Node.js version supports both. Data applications operating with large datasets over the wire can benefit from enabling compression. Currently, onlyGZIP is supported using zlib.
response: trueinstructs ClickHouse server to respond with compressed response body. Default value:response: falserequest: trueenables compression on the client request body. Default value:request: false
Logging (Node.js only)
The default logger implementation emits log records intostdout via console.debug/info/warn/error methods.
You can customize the logging logic via providing a LoggerClass, and choose the desired log level via level parameter (default is OFF):
TRACE- low-level information about the Keep-Alive sockets life cycleDEBUG- response information (without authorization headers and host info)INFO- mostly unused, will print the current log level when the client is initializedWARN- non-fatal errors; failedpingrequest is logged as a warning, as the underlying error is included in the returned resultERROR- fatal errors fromquery/insert/exec/commandmethods, such as a failed request
TLS certificates (Node.js only)
Node.js client optionally supports both basic (Certificate Authority only) and mutual (Certificate Authority and client certificates) TLS. Basic TLS configuration example, assuming that you have your certificates incerts folder
and CA file name is CA.pem:
Keep-alive configuration (Node.js only)
The client enables Keep-Alive in the underlying HTTP agent by default, meaning that the connected sockets will be reused for subsequent requests, andConnection: keep-alive header will be sent. Sockets that are idling will remain in the connection pool for 2500 milliseconds by default (see the notes about adjusting this option).
keep_alive.idle_socket_ttl is supposed to have its value a fair bit lower than the server/LB configuration. The main reason is that due to HTTP/1.1 allowing the server to close the sockets without notifying the client, if the server or the load balancer closes the connection before the client does, the client could try to reuse the closed socket, resulting in a socket hang up error.
If you are modifying keep_alive.idle_socket_ttl, keep in mind that it should be always in sync with your server/LB Keep-Alive configuration, and it should be always lower than that, ensuring that the server never closes the open connection first.
Adjusting idle_socket_ttl
The client sets keep_alive.idle_socket_ttl to 2500 milliseconds, as it can be considered the safest default; on the server side keep_alive_timeout might be set to as low as 3 seconds in ClickHouse versions prior to 23.11 without config.xml modifications.
You can find the correct Keep-Alive timeout value in the server response headers by running the following command:
Connection and Keep-Alive headers in the response. For example:
keep_alive_timeout is 10 seconds, and you could try increasing keep_alive.idle_socket_ttl to 9000 or even 9500 milliseconds to keep the idling sockets open for a bit longer than by default. Keep an eye on potential “Socket hang-up” errors, which will indicate that the server closes the connections before the client does so, and lower the value until the errors disappear.
Troubleshooting
If you are experiencingsocket hang up errors even when using the latest version of the client, there are the following options to resolve this issue:
-
Enable logs with at least
WARNlog level. This will allow for checking if there is an unconsumed or a dangling stream in the application code: the transport layer will log it on the WARN level, as that could potentially lead to the socket being closed by the server. You can enable logging in the client configuration as follows: - Check your application code with no-floating-promises ESLint rule enabled, which will help to identify unhandled promises that could lead to dangling streams and sockets.
-
Slightly reduce
keep_alive.idle_socket_ttlsetting in the ClickHouse server configuration. In certain situations, for example, high network latency between client and server, it could be beneficial to reducekeep_alive.idle_socket_ttlby another 200–500 milliseconds, ruling out the situation where an outgoing request could obtain a socket that the server is going to close. -
If this error is happening during long-running queries with no data coming in or out (for example, a long-running
INSERT FROM SELECT), this might be due to the load balancer closing idling connections. You could try forcing some data coming in during long-running queries by using a combination of these ClickHouse settings:Keep in mind, however, that the total size of the received headers has 16KB limit in recent Node.js versions; after certain amount of progress headers received, which was around 70-80 in our tests, an exception will be generated. It is also possible to use an entirely different approach, avoiding wait time on the wire completely; it could be done by leveraging HTTP interface “feature” that mutations are not cancelled when the connection is lost. See this example (part 2) for more details. -
Keep-Alive feature can be disabled entirely. In this case, client will also add
Connection: closeheader to every request, and the underlying HTTP agent will not reuse the connections.keep_alive.idle_socket_ttlsetting will be ignored, as there will be no idling sockets. This will result in additional overhead, as a new connection will be established for every request.
Read-only users
When using the client with a readonly=1 user, the response compression cannot be enabled, as it requiresenable_http_compression setting. The following configuration will result in an error:
Proxy with a pathname
If your ClickHouse instance is behind a proxy, and it has pathname in the URL as in, for example, http://proxy:8123/clickhouse_server, specifyclickhouse_server as pathname configuration option (with or without a leading slash); otherwise, if provided directly in the url, it will be considered as the database option. Multiple segments are supported, e.g. /my_proxy/db.
Reverse proxy with authentication
If you have a reverse proxy with authentication in front of your ClickHouse deployment, you could use thehttp_headers setting to provide the necessary headers there:
Custom HTTP/HTTPS agent (experimental, Node.js only)
By default, the client will configure the underlying HTTP(s) agent using the settings provided in the client configuration (such asmax_open_connections, keep_alive.enabled, tls), which will handle the connections to the ClickHouse server. Additionally, if TLS certificates are used, the underlying agent will be configured with the necessary certificates, and the correct TLS auth headers will be enforced.
After 1.2.0, it is possible to provide a custom HTTP(s) agent to the client, replacing the default underlying one. It could be useful in case of tricky network configurations. The following conditions apply if a custom agent is provided:
- The
max_open_connectionsandtlsoptions will have no effect and will be ignored by the client, as it is a part of the underlying agent configuration. keep_alive.enabledwill only regulate the default value of theConnectionheader (true->Connection: keep-alive,false->Connection: close).- While the idle keep-alive socket management will still work (as it is not tied to the agent but to a particular socket itself), it is now possible to disable it entirely by setting the
keep_alive.idle_socket_ttlvalue to0.
Custom agent usage examples
Using a custom HTTP(s) Agent without certificates:set_basic_auth_header setting (introduced in 1.2.0), as it conflicts with the TLS headers. All the TLS headers should be provided manually.
Known limitations (Node.js/web)
- There are no data mappers for the result sets, so only language primitives are used. Certain data type mappers are planned with RowBinary format support.
- There are some Decimal* and Date* / DateTime* data types caveats.
- When using JSON* family formats, numbers larger than Int32 are represented as strings, as Int64+ types maximum values are larger than
Number.MAX_SAFE_INTEGER. See the Integral types section for more details.
Known limitations (web)
- Streaming for select queries works, but it is disabled for inserts (on the type level as well).
- Request compression is disabled and configuration is ignored. Response compression works.
- No logging support yet.
Tips for performance optimizations
- To reduce application memory consumption, consider using streams for large inserts (e.g. from files) and selects when applicable. For event listeners and similar use cases, async inserts could be another good option, allowing to minimize, or even completely avoid batching on the client side. Async insert examples are available in the client repository, with
async_insert_as the file name prefix. - The client does not enable request or response compression by default. However, when selecting or inserting large datasets, you could consider enabling it via
ClickHouseClientConfigOptions.compression(either for justrequestorresponse, or both). - Compression has significant performance penalty. Enabling it for
requestorresponsewill negatively impact the speed of selects or inserts, respectively, but will reduce the amount of network traffic transferred by the application.
Contact us
If you have any questions or need help, feel free to reach out to us in the Community Slack (#clickhouse-js channel) or via GitHub issues.