Query CSV and TSV Files with SQL in Your Browser

Load a .csv or .tsv file and run SQL queries in your browser using DuckDB-WASM. Automatic type inference, delimiter detection, and instant schema preview, with no install needed.

ZERO UPLOAD · ALL LOCAL
  1. Drop a file onto the drop zone — or click it to browse. Supported: Parquet, Arrow, Feather, CSV, TSV, JSON, NDJSON, Avro, DBF, Excel (.xlsx), SQLite (.db/.sqlite).
  2. The query engine pre-loads in the background (~2 MB, one-time per session). Your file is indexed immediately after.
  3. Browse the schema accordion to see tables and column types.
  4. Type a SQL query in the editor and click Run Query.
  5. Results appear in the grid below. Click Export, then choose CSV, JSON, Excel, or Parquet to download the full result set.

These examples show the query only. Load a matching data file first, then use Load into tool to try it.

Worked examples for this use case

Count rows and check for duplicates

Example
SELECT COUNT(*) AS total,
       COUNT(DISTINCT id) AS unique_ids
FROM customers;

If total and unique_ids differ, you have duplicate id values in the CSV.

Aggregate by a category column

Example
SELECT category, SUM(revenue) AS total_revenue
FROM sales
GROUP BY category
ORDER BY total_revenue DESC;

DuckDB infers numeric types from the first rows — confirm with DESCRIBE sales before aggregating.

Cast an incorrectly inferred column type

Example
SELECT zip_code::VARCHAR AS zip,
       city,
       state
FROM addresses
WHERE state = 'CA';

DuckDB may infer a ZIP code column as BIGINT. Cast it to VARCHAR to avoid losing leading zeros.

Filter rows and export a subset

Example
SELECT *
FROM orders
WHERE order_date >= '2026-01-01'
  AND status = 'fulfilled';

Use the Export button after running this query to download the filtered subset as CSV, JSON, Excel, or Parquet.

Zero upload guarantee

Your database file never leaves this device. DuckDB runs locally via WebAssembly — no server, no account, no logs.

Drop a file here — Parquet, CSV, JSON, Excel, Arrow, and more

or click to select · .parquet · .csv · .json · .xlsx · .arrow · .feather · .tsv · .ndjson · .avro · .dbf · .db · .sqlite

Loading DuckDB engine…

SCHEMA

Running query…

RESULTS

Query CSV and TSV Files with SQL in Your Browser

When CSV exports land on your desk, they often look too simple to query. Every spreadsheet tool, database, and API can produce them, yet those plain text files still carry enough structure for serious analysis.1 The SQL Workbench reads both CSV and TSV with DuckDB, automatically detecting delimiters and inferring column types, so you can run GROUP BY, JOIN, and window function queries without writing any Python.

Why SQL on CSV beats a spreadsheet for data work

Spreadsheets handle a few thousand rows comfortably. Beyond that, scrolling and manual filtering become impractical, pivot tables slow down, and formula errors multiply. SQL does not share those constraints. DuckDB reads CSV files row by row without loading the entire file into memory at once, making it practical to query files with millions of rows in a browser tab. Furthermore, SQL is reproducible: a query you save and re-run tomorrow produces the same result, whereas a series of spreadsheet filter clicks does not. For tasks like aggregating log exports, summarising survey data, or cross-tabulating report outputs, SQL on CSV is faster to write and easier to verify than equivalent spreadsheet work.2

How the workbench loads CSV and TSV files

Drop a .csv file and DuckDB sniffs the delimiter, quoting character, and column types automatically. Tab-separated files use an explicit tab delimiter, so .tsv files load correctly without any configuration. The view name comes from the file stem: sales_2026_q1.csv becomes the view sales_2026_q1. For files with non-standard headers or leading whitespace, the sniffer still identifies the column boundary positions correctly. This automatic detection process is what makes the workbench practical for CSV exploration, because you can run meaningful queries on an unfamiliar file without first inspecting its contents in a text editor.3

Type inference and schema preview

DuckDB inspects the first rows to infer types: integers become BIGINT, decimals become DOUBLE, ISO date strings become DATE or TIMESTAMP, and everything else becomes VARCHAR. The workbench shows a schema preview and runs SELECT * FROM table LIMIT 10 on its own before you write anything. If DuckDB infers a type incorrectly (a ZIP code column read as INTEGER, for example), you can cast it in your query: SELECT zip_code::VARCHAR FROM addresses. The preview also reveals whether the header row was parsed correctly, so you can spot offset columns before writing aggregation queries.

Because the sniffer reads only a sample of leading rows, a column that looks numeric at the top can turn out to contain text further down, and DuckDB still declares it VARCHAR to stay safe. When you know a column is numeric throughout, an explicit cast keeps your aggregations from silently returning zero rows. Reviewing the preview before writing GROUP BY or JOIN logic is the fastest way to avoid a query that runs but reports the wrong totals.

Practical query patterns for CSV data

Start with DESCRIBE to confirm column names and inferred types, then run a LIMIT query to scan a few rows. From there, GROUP BY aggregations identify the shape of the data: SELECT category, COUNT(*) FROM products GROUP BY category ORDER BY COUNT(*) DESC. Filtering with WHERE, sorting with ORDER BY, and computing derived columns with expressions all work exactly as in any SQL database. Window functions such as ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC) rank rows while preserving each row's identity.4

Because the workbench loads one file at a time, JOINs across two separate CSV files are not directly possible. Within a single file, self-joins and subqueries work normally. For a quick cross-check on data quality, SELECT COUNT(*) AS total, COUNT(DISTINCT id) AS unique_ids FROM table reveals duplicate key problems instantly.

Handling encoding and delimiter detection problems

Handling a CSV that fails to load correctly usually comes down to two issues: wrong encoding or wrong delimiter. DuckDB's CSV sniffer handles comma, semicolon, pipe, and tab delimiters automatically, but it may guess incorrectly for unusual files.5 When the sniffer picks the wrong delimiter, your data loads as one large VARCHAR column per row rather than individual typed columns. The symptom is DESCRIBE returning a single column named something like column0 with all values being long strings.

Overriding the delimiter and encoding

If automatic detection fails, override it with a custom read_csv query: SELECT * FROM read_csv('myfile.csv', delim=';', header=true). Replace ; with the correct delimiter for your file. For TSV files with a .csv extension, use delim='\t'. Encoding issues appear as replacement characters or garbled accented text in query results, and they are especially common when a file uses Windows-1252 or Latin-1 rather than UTF-8. Convert such files to UTF-8 first using most text editors or the iconv command-line tool, which handle this conversion reliably.

Multi-file analysis when the workbench loads one CSV at a time

When you need to compare or join data from two separate CSV files, you have two practical options within the one-file-per-session constraint. The first option is to concatenate the rows before loading: combine both CSVs into a single file using a command-line tool, then load the combined file and use a source discriminator column to distinguish which file each row came from.

Comparing files without direct multi-file joins

The second option applies when the files have different schemas and you need to join them on a key column. Export one file to SQLite using a tool like csvkit's csvsql insert command, load the SQLite database in the workbench, then query across both tables from the single database file.6 For repeated multi-file workflows, loading the data into a local SQLite database once and querying the .db file is more efficient than preprocessing on each workbench session. Pasting either the concatenated file or the SQLite export into the workbench gives you two CSV files joined without a server.

When to use this

Use this when you have a CSV export from a CRM, a database dump, a spreadsheet export, or an API response saved to disk and want to run SQL against it without installing anything.

Examples

Count rows and check for duplicates

Before
SELECT COUNT(*) AS total,
       COUNT(DISTINCT id) AS unique_ids
FROM customers;

If total and unique_ids differ, you have duplicate id values in the CSV.

Aggregate by a category column

Before
SELECT category, SUM(revenue) AS total_revenue
FROM sales
GROUP BY category
ORDER BY total_revenue DESC;

DuckDB infers numeric types from the first rows — confirm with DESCRIBE sales before aggregating.

Cast an incorrectly inferred column type

Before
SELECT zip_code::VARCHAR AS zip,
       city,
       state
FROM addresses
WHERE state = 'CA';

DuckDB may infer a ZIP code column as BIGINT. Cast it to VARCHAR to avoid losing leading zeros.

Filter rows and export a subset

Before
SELECT *
FROM orders
WHERE order_date >= '2026-01-01'
  AND status = 'fulfilled';

Use the Export button after running this query to download the filtered subset as CSV, JSON, Excel, or Parquet.

Sources
  1. 1.

    Y. Shafranovich, "Common Format and MIME Type for Comma-Separated Values (CSV) Files," RFC 4180, IETF, October 2005. https://www.rfc-editor.org/info/rfc4180/

  2. 2.

    DuckDB Foundation, "CSV Import," duckdb.org, accessed June 2026. https://duckdb.org/docs/current/data/csv/overview

  3. 3.

    DuckDB Foundation, "CSV Auto Detection," duckdb.org, accessed June 2026. https://duckdb.org/docs/current/data/csv/auto_detection

  4. 4.

    PostgreSQL Global Development Group, "Window Functions," postgresql.org, June 2026. https://www.postgresql.org/docs/current/tutorial-window.html

  5. 5.

    DuckDB, "dialect_detection.cpp," github.com, accessed June 2026. https://github.com/duckdb/duckdb/blob/main/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp

  6. 6.

    wireservice, "csvsql," github.com, accessed June 2026. https://github.com/wireservice/csvkit/blob/master/docs/scripts/csvsql.rst

FAQ