Why browser-based SQL?
Inspecting a data file should not require a database server. Yet most SQL
tools still ask you to install software, keep a daemon running, or upload
your file to a cloud service before you can write a single query. For a
one-off look at a Parquet export or a CSV dropped by a pipeline, that
setup cost dwarfs the actual work. A browser tab erases it.
Privacy raises the stakes further. Database files and analytics exports routinely carry personal data, access tokens, or revenue figures that have no business leaving your machine. Because every query here runs inside your own browser tab, the workbench never sends your file anywhere, and you can prove it by going offline mid-session and watching the tool carry on. CapyToolkit does not upload, store, or collect the data you load.
DuckDB-WASM engine
Running real SQL with no server of any kind takes a specific engine, and
that engine is DuckDB. The workbench embeds DuckDB compiled to WebAssembly, a fast analytical database built for the scan-heavy, aggregate-heavy
queries you write when you are exploring data rather than serving an
application.1 It reads Parquet,
CSV, JSON, and newline-delimited JSON files natively.2 Because each query executes in a Web Worker, a slow aggregation never freezes
the page you are typing into.3
The engine binary loads exactly once. It comes from this site's own CDN rather than a third-party host, downloads a single time per session, and your browser caches it from then on. After that first load, the workbench keeps working with no network connection at all. Pull the file, write a query, read the result, every step offline.
A concrete run shows the shape of a typical query. Loading a three-column orders.csv
file (id, category, amount) with a few hundred rows and
running SELECT category, COUNT(*) AS n, SUM(amount) AS total FROM orders GROUP BY category
ORDER BY n DESC returns one row per distinct category, each with its order count and revenue
total, sorted from the busiest category down. The grid updates the moment the query finishes, and
Export turns that same result set into CSV, JSON, Excel, or
Parquet without re-running anything.
Import formats
That engine accepts far more than database files. When you drop a file,
the workbench routes it to one of three loaders: DuckDB reads the columnar
and text formats directly, a JavaScript bridge decodes the formats DuckDB
cannot open on its own, and SQLite files go through a dedicated reader.
Once a file is loaded, you query it the same way no matter which path it
took. Here is what the workbench accepts:
Columnar and text formats
Parquet and GeoParquet (.parquet). DuckDB reads Parquet natively, pruning columns and pushing filters down
so wide files stay quick.2 GeoParquet files
store geometry columns as WKB or GeoArrow encodings with Parquet metadata,
so without a spatial extension the geometry payload arrives as binary data
rather than a mapped feature layer.4 Arrow and Feather (.arrow, .feather). These columnar formats load into a view named after the file. Drop orders.arrow and you can immediately run SELECT * FROM orders.
CSV and TSV (.csv, .tsv). CSV records are line-oriented fields separated by commas, with optional
headers, and DuckDB auto-detects the header row and column schema
automatically.5 Tab-separated
files are read with an explicit tab delimiter. Each becomes a view named after
the file stem. JSON and NDJSON (.json, .jsonl, .ndjson). JSON represents structured data with objects and arrays, while JSON Lines stores one valid JSON value per line for log-style streams.6 The workbench reads both shapes into queryable rows without a conversion
step.
Formats decoded in JavaScript
Avro (.avro). Avro container files are decoded in the browser, and the schema stored with the data tells the reader how to interpret each record.7 DBF (.dbf). DBF-style table files store a header record, field subrecords, and fixed-width data records, so the browser parser can turn them into a single queryable table.8 Excel (.xlsx). SpreadsheetML workbooks contain worksheet parts, and each worksheet is a grid of rows and cells, so every sheet becomes its own table with headers taken from the first row.9
SQLite files
SQLite (.sqlite, .db).
SQLite database files open through sql.js, a build of SQLite compiled to
WebAssembly that loads the entire file into memory so no byte ever leaves
the browser.10 The same
library can also create a fresh database if you open the workbench with no
file at all. Whichever extension the existing file uses, every table inside
is ready to query at once.
Whichever format you started from, the result is the same. The schema
panel lists every table and column type the instant loading finishes, and
a preview query runs on its own so you see real rows before typing
anything. From that point on, exploring a Parquet export and exploring an
Excel sheet are the same task.
Export formats
Reading data is only half the job. Getting an answer back out is the other
half, and the Export button in the results panel handles it with four
choices. CSV writes a standard comma-separated file, and JSON gives you an
array of objects with one entry per row. For spreadsheet users, the Excel
option produces a single-sheet .xlsx workbook.9 Parquet works differently. Rather than serializing the rows already on screen,
it runs a COPY ... TO statement back through DuckDB, so the download
matches exactly what the SQL engine produced.11 The same
path works for any query result, not only stored tables, because DuckDB can
copy the output of a SELECT straight to Parquet. That path depends on
DuckDB, which is why Parquet export is offered for every DuckDB-loaded format
but stays disabled during a SQLite session.
SQL dialect support
Formats and loaders are plumbing; the SQL is where the work happens.
DuckDB combines standard SQL patterns with DuckDB's friendly SQL
extensions, so the features you reach for in a production warehouse are
present here.12 Reach for a window
function like ROW_NUMBER(), RANK(), or LAG(), and it works with no configuration at all. UNNEST flattens arrays
inline, while PIVOT and UNPIVOT rotate a table without
a single CTE. When a quick type conversion is all you want, the :: operator keeps it short, as in price::DOUBLE.
DuckDB-friendly extensions
A handful of DuckDB conveniences are worth committing to memory. QUALIFY filters window-function results without wrapping the query in a subquery.
With SELECT * EXCLUDE (col) you project every column but the ones
you name, and SELECT * REPLACE (expr AS col) rewrites a column
inline. One caveat applies to SQLite files: because they run through sql.js
rather than DuckDB, they speak standard SQLite SQL, not DuckDB's dialect.
Choosing the right format for your data
Format choice affects query speed, file size, and what tools downstream
can consume. Parquet is the right starting point for most analytical work
because DuckDB reads it column by column, skipping entire column groups
when a query touches only a subset of fields. A 20-column file where your
query filters on one column and returns two others lets DuckDB skip
reading the remaining seventeen entirely. The result is query times that
feel fast on files well above what fits in RAM, because the engine never
loads the data it does not need. Parquet also stores page-level statistics
that readers can use to skip pages during selective scans.13
CSV stays the universal interchange format. Every tool reads it, every
tool writes it, and that universality makes it the right choice when you
need to share results with colleagues who work in different environments,
or when the data source exports in no other format.5 The downside is that CSV carries no type information: every column arrives
as a string until something infers otherwise. DuckDB's type sniffer handles
this well for well-formed data, but ambiguous dates and numbers formatted with
locale-specific separators may need a manual CAST in the first query after loading.
JSON works similarly to CSV in accessibility but preserves nested objects and
arrays that CSV flattens, making it useful for API response logs where the original
hierarchy matters for the analysis.6
Excel makes sense when the data source is a human-maintained spreadsheet
rather than a machine-generated export. Loading a .xlsx file directly
avoids the manual export-to-CSV step that introduces encoding problems and
strips formula-computed values. SQLite suits situations where you already
have a small embedded database and want to run ad hoc queries without
setting up a database server: drop the file in, write standard SQL, and
explore the schema from the accordion panel. For exporting results,
Parquet is a compact analytical format, while CSV and JSON suit situations
where the recipient needs to open the file in a general-purpose tool
without a query engine. Picking the right
format at import and export avoids a conversion step that adds time and the
risk of data loss between tools.
Picked the Right Loader Checklist
- Parquet for analytical work DuckDB reads it column by column and skips whole column groups your query never touches.
- CSV for universal interchange Every tool reads and writes it, but it carries no type information — check DuckDB's auto-detected column types before trusting a CAST.
- Excel for human-maintained spreadsheets Loading .xlsx directly skips the manual export-to-CSV step that strips formula-computed values.
- SQLite for an existing embedded database Runs through sql.js and speaks standard SQLite SQL, not DuckDB's dialect.
Drop your own file above and match its format against this list before writing a query.
- 1.
DuckDB Foundation, "DuckDB-Wasm," github.com, accessed June 2026. https://github.com/duckdb/duckdb-wasm
- 2.
Apache Software Foundation, "Column Chunks," parquet.apache.org, January 2024. https://parquet.apache.org/docs/file-format/data-pages/columnchunks/
- 3.
MDN Contributors, "Web Workers API," developer.mozilla.org, April 2025. https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
- 4.
GeoParquet Contributors, "GeoParquet Specification," geoparquet.org, accessed June 2026. https://geoparquet.org/releases/v1.1.0/
- 5.
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/
- 6.
T. Bray, "The JavaScript Object Notation (JSON) Data Interchange Format," RFC 8259, IETF, December 2017. https://www.rfc-editor.org/info/rfc8259/
- 7.
Apache Software Foundation, "Specification," avro.apache.org, accessed June 2026. https://avro.apache.org/docs/1.12.0/specification/
- 8.
Microsoft Learn, "Table File Structure (.dbc, .dbf, .frx, .lbx, .mnx, .pjx, .scx, .vcx)," learn.microsoft.com, June 2008. https://learn.microsoft.com/en-us/previous-versions/st4a0s68(v=vs.90)
- 9.
Microsoft Learn, "Working with sheets," learn.microsoft.com, January 2025. https://learn.microsoft.com/en-us/office/open-xml/spreadsheet/working-with-sheets?tabs=cs
- 10.
sql-js Contributors, "sql.js," github.com, accessed June 2026. https://github.com/sql-js/sql.js
- 11.
DuckDB Foundation, "Parquet Export," duckdb.org, accessed June 2026. https://duckdb.org/docs/current/guides/file_formats/parquet_export
- 12.
DuckDB Foundation, "Friendly SQL," duckdb.org, accessed June 2026. https://duckdb.org/docs/current/sql/dialect/friendly_sql
- 13.
Apache Software Foundation, "Page Index," parquet.apache.org, February 2026. https://parquet.apache.org/docs/file-format/pageindex/