Working with Parquet, CSV & JSON Files
One of DuckDB’s signature capabilities: you can run SQL directly against files on disk (or in cloud storage) with no import or loading step. The file is the table.
Parquet
SELECT * FROM 'orders.parquet' LIMIT 10;
-- Multiple files via globSELECT * FROM 'sales/2026-*.parquet';
-- Explicit function form (equivalent, useful when passing options)SELECT * FROM read_parquet(['sales/jan.parquet', 'sales/feb.parquet']);DuckDB reads Parquet’s column statistics and row-group metadata to skip data that can’t match your filters — so WHERE order_date > '2026-06-01' on a partitioned Parquet dataset can be nearly as fast as a proper index lookup, without one existing.
CSV
SELECT * FROM read_csv_auto('customers.csv');
-- Explicit schema/options when auto-detection needs helpSELECT * FROM read_csv('customers.csv', header = true, delim = ',', columns = {'id': 'INTEGER', 'name': 'VARCHAR', 'signup_date': 'DATE'});read_csv_auto sniffs the delimiter, header row, and column types automatically — it gets it right for the large majority of real-world CSVs without any options.
JSON
SELECT * FROM read_json_auto('events.jsonl'); -- newline-delimited JSONSELECT * FROM read_json_auto('payload.json'); -- single JSON document/arrayQuerying Across Formats in One Query
Because each of these is just a table reference, you can join a Parquet file to a CSV file to a live table in the same query:
SELECT c.name, o.totalFROM read_csv_auto('customers.csv') cJOIN 'orders.parquet' o ON c.id = o.customer_id;Writing Data Out
COPY (SELECT * FROM orders WHERE order_date >= '2026-01-01')TO 'orders_2026.parquet' (FORMAT parquet);
COPY orders TO 'orders.csv' (HEADER, DELIMITER ',');COPY ... TO accepts the same FORMAT parquet | csv | json options as reading, plus PARTITION_BY for writing out a Hive-style partitioned directory tree:
COPY orders TO 'orders_by_year' (FORMAT parquet, PARTITION_BY (year));This makes DuckDB a genuinely useful ETL tool in its own right — reshape, filter, and repartition large file-based datasets with SQL, no separate ingestion pipeline required.