Querying Parquet, CSV, and JSON Files Directly in DuckDB

Use DuckDB to query Parquet, CSV, and JSON files directly from disk with zero loading step, handle globs of multiple files, and export results back out.

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 glob
SELECT * 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 help
SELECT * 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 JSON
SELECT * FROM read_json_auto('payload.json'); -- single JSON document/array

Querying 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.total
FROM read_csv_auto('customers.csv') c
JOIN '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.