Export streams straight to disk — even a whole script
The result grid caps rows so your browser survives. Export doesn't use the grid at all.
A SQL console has a tension baked in. To stay responsive it caps how many rows it shows — we default to 500. But sometimes you don't want to look at the data, you want to take it: dump a table to Parquet, hand a CSV to a colleague, feed a pipeline. Capping is exactly wrong for that, and buffering a few million rows in a browser tab to assemble a download is how you OOM the tab.
So Export doesn't touch the grid. Click Export, pick a file, and the browser streams
ClickHouse's response body straight to disk — resp.body piped into a file opened
through the File System Access API. Nothing is buffered in the page; memory stays flat whether the
result is a thousand rows or a billion. It runs uncapped — a file has no scroll
performance to protect.
The format is the query
You don't choose a format from a menu — you write it. End the query with
FORMAT Parquet and you get a .parquet;
CSV → .csv; JSONEachRow →
.jsonl; Arrow, ORC, Avro, Native, even SQLInsert —
ClickHouse's whole format family, streamed verbatim, with the right extension picked for you. No
FORMAT clause and you get TabSeparatedWithNames, the
.tsv that opens cleanly in Excel or pandas. The console isn't re-serializing
anything — ClickHouse formats the bytes, they flow to the file.
SELECT * FROM github.github_events FORMAT Parquet
→ github_events.parquet streaming… 4.2 GB · 12s · Cancel
Even a whole script
Here's the part I like. Point Export at a multi-statement script — the same
;-separated scripts multiquery runs — and instead
of a file picker you get a directory picker. Each statement runs in order in one
shared session, and every row-returning statement streams uncapped to its own file, numbered to match
the log:
etl-nightly/ 001-raw-events.parquet 4.2 GB 002-daily-rollup.csv 18 MB 003-top-accounts.tsv 2.1 MB
Effectful statements — CREATE, INSERT — run for effect
and just log OK. Because it's one session, a CREATE TEMPORARY TABLE in step 1 is
still there for the SELECT in step 3. A live log shows status, file, bytes and elapsed per statement —
metadata only, never the rows, so exporting a script that emits gigabytes doesn't cost the tab a thing.
A nightly-extract that used to be a shell loop of
clickhouse-client --queries-file redirects is now: paste, Export, pick a folder.
It won't hand you a broken file
Streaming has a nasty failure mode. Once the HTTP response has started, its 200
is locked in — so a ClickHouse error partway through can't come back as a status code. It arrives as
text, in the middle of your data. Pipe that straight to disk and the error becomes a corrupt
row in your Parquet file that you discover much later.
Export guards against it. ClickHouse tags a mid-stream failure — an
X-ClickHouse-Exception-Tag header and a trailing exception frame — and the writer
holds back the tail of the stream until it can confirm the end is clean, excising that frame before it
ever reaches disk. A failed export says "Export incomplete"; it never bakes the error
into your file. Cancel works the same way: it aborts the stream and issues its own
KILL QUERY, independent of whatever the result grid is doing.
It's Chromium-only for now — the File System Access API isn't everywhere yet, and the button tells you
when it can't run. If you're on Chrome, paste a SELECT … FORMAT Parquet on the
demo and hit Export, or point it at a script and
watch a folder fill up.