Skip to content

How to Export ClickHouse Data to CSV (5 Practical Methods)

Learn how to export ClickHouse data to CSV using clickhouse-client, the HTTP interface, TSV/custom delimiters, gzip compression, chunked exports, and direct S3 export. A quick, practical tutorial with copy-paste examples.

Dasun Kalupahana 3 min read 168 views 0 comments
On this page
  1. 1. The simplest way: clickhouse-client with --format
  2. 2. Exporting over HTTP
  3. 3. Choosing a different delimiter
  4. 4. Compressing the output
  5. 5. Handling tables too big for one export
  6. Common gotchas
  7. Wrapping up

If you work with ClickHouse, sooner or later you'll need to get data out of it and into a CSV file — for a report, a handoff to another system, or just a quick backup of an aggregated result. ClickHouse makes this easy once you know which method fits your situation. Here's a fast, practical rundown of the main ways to do it.


1. The simplest way: clickhouse-client with --format

The most common approach is running a query through the command-line client and telling it to output CSV:

clickhouse-client \
  --host your-clickhouse-host \
  --user default \
  --password your_password \
  --query "SELECT order_id, customer_id, total_amount, created_at FROM orders WHERE created_at >= yesterday()" \
  --format CSVWithNames \
  > orders_export.csv

The key part here is --format CSVWithNames. Swap in plain CSV if you don't want a header row, or use CSVWithNamesAndTypes if you also want column data types included — handy when a downstream tool needs to know the schema without guessing.


2. Exporting over HTTP

If you don't have clickhouse-client installed, or you're triggering the export from a script or another service, ClickHouse's built-in HTTP interface works just as well:

curl -G 'http://your-clickhouse-host:8123/' \
  --data-urlencode "query=SELECT order_id, customer_id, total_amount, created_at FROM orders WHERE created_at >= yesterday() FORMAT CSVWithNames" \
  -H 'X-ClickHouse-User: default' \
  -H 'X-ClickHouse-Key: your_password' \
  -o orders_export.csv

Notice the format is specified inside the query itself with FORMAT CSVWithNames rather than as a separate flag. This is a small but easy-to-miss difference between the CLI and HTTP approaches.


3. Choosing a different delimiter

CSV isn't always the right fit — sometimes you need tab-separated values for a spreadsheet import, or a custom delimiter for a legacy pipeline. ClickHouse supports both:

# Tab-separated
clickhouse-client \
  --query "SELECT device_id, sensor_type, reading_value, recorded_at FROM sensor_readings" \
  --format TabSeparatedWithNames \
  > sensor_readings.tsv

For anything more unusual (pipes, semicolons, etc.), the CustomSeparated format lets you define your own separator via a format schema.


4. Compressing the output

Large exports can get big fast. Rather than exporting first and compressing afterward, pipe the output straight into gzip so you never write an uncompressed file to disk:

clickhouse-client \
  --query "SELECT * FROM orders" \
  --format CSVWithNames \
  | gzip > orders.csv.gz

This is a good default for anything you're archiving or shipping over a network — it saves both disk space and transfer time.


5. Handling tables too big for one export

If a table is large enough that a single query times out or eats too much memory, split the export by date range (or any other natural partition key) and loop through it:

for month in 2026-07 2026-08 2026-09; do
  clickhouse-client \
    --query "SELECT * FROM orders WHERE toYYYYMM(created_at) = replace('${month}', '-', '')" \
    --format CSVWithNames \
    > "orders_${month}.csv"
done

This keeps each individual query small and predictable, and gives you resumability — if one month fails, you only need to re-run that chunk, not the whole export.


Common gotchas

  • Quoting and special characters: CSV output escapes commas and quotes automatically, but if a downstream tool is picky about encoding, double-check with CSVWithNamesAndTypes to see the raw types being emitted.
  • Large result sets and memory: if a query is timing out, that's usually a sign to add a WHERE clause or chunk the export (see method 5), not to increase timeouts indefinitely.
  • Permissions: the HTTP interface requires the same read permissions as the CLI — a common source of "empty file" confusion is actually an auth failure being silently written to the output file instead of raising an error you'd notice.

Wrapping up

For a one-off query, clickhouse-client --format CSVWithNames is the fastest path. For automation or environments without the CLI installed, the HTTP interface does the same job. Compress large exports with gzip, chunk anything too big to fit in one query, and consider exporting directly to S3 if that's where the file needs to end up anyway.

Free tools for this topic

Code snippets and fixes for this topic

Get one practical tip every week

New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.

Have a question about this post?

Ask the community: other developers and the author can answer.

Ask the community

Get notified about new articles

One click, no email needed. Turn it off anytime with the bell at the top.

Get new articles on your iPhone

Add DEV Talk to your Home Screen, open it, then tap the bell.

Rate this post
0.0
Share

Enjoying the content?

If this article helped you, you can support the author with a coffee. It keeps new posts coming.

Buy me a coffee (opens in a new tab)

Comments 0

Be kind. Comments with links are reviewed before they appear.

No comments yet

Be the first to share your thoughts.

Get new articles in your inbox

Practical tutorials and deep dives, about once a week. No spam, unsubscribe anytime.

Privacy policy

Add DEV Talk to your Home Screen

  1. 1 Tap the Share button in Safari's toolbar.
  2. 2 Scroll down and tap Add to Home Screen.
  3. 3 Tap Add. Open it from the Home Screen to read like an app and to turn on notifications with the bell.

We use cookies to improve your experience and analyze traffic. By continuing, you agree to our Privacy Policy.