Query CSV files with SQL
Pick a folder of CSV files and query them with SQL. Each file is imported into SQLite as a table named after the file, so you can join, filter, group and aggregate across files, then save the result as a CSV file or keep a SQLite database. It runs in this tab; your data is never uploaded.
Run it on your folder
Nothing is downloaded until you press Run. Works in current Chrome, Edge, Firefox and Safari; saving straight back into the folder needs Chrome or Edge.
What you can do
Run a query
Imports every CSV file as a table and prints the query result as a table.
sqlite3 :memory: '.import --csv regions.csv regions' '.import --csv sales.csv sales' '.mode table' 'SELECT * FROM regions LIMIT 20;'
Save the result as CSV
Runs the query and writes the result, with a header row, to a CSV file in out/.
mkdir -p out && sqlite3 :memory: '.import --csv regions.csv regions' '.import --csv sales.csv sales' '.headers on' '.mode csv' '.once out/'result.csv 'SELECT * FROM regions LIMIT 20;'
Build a SQLite database
Imports every CSV file into one SQLite database file, out/data.db, that any SQLite tool can open.
mkdir -p out && rm -f out/data.db && sqlite3 out/data.db '.import --csv regions.csv regions' '.import --csv sales.csv sales' '.tables'
Show tables and columns
Imports the CSV files and prints the table definitions SQLite derived from their header rows.
sqlite3 :memory: '.import --csv regions.csv regions' '.import --csv sales.csv sales' '.schema'
How it works
- Pick a folder. Choose the folder with your CSV files. They are copied into a sandbox in this browser tab, not uploaded.
- Write a query. Each CSV file is a table named after the file. Write SQL against those tables: SELECT, JOIN, GROUP BY, window functions.
- Run SQLite. Press Run. The sqlite3 shell, compiled to WebAssembly, imports the files and runs the query.
- Keep the result. Read the result table, or save it as a CSV file or a SQLite database into your folder or a zip download.
Under the hood the page boots NanoVM, a Linux userland compiled to WebAssembly, in this tab. Your folder is copied into its in-memory filesystem at /work, and a BusyBox shell runs the command, which starts sqlite3 on the WebAssembly (WASI) runner. The Terminal tab opens the same folder in an interactive shell, for anything the presets don’t cover.
Your files stay on your device
Your CSV files are read by your browser and copied into an in-memory filesystem inside this tab, where the sqlite3 shell (compiled to WebAssembly) imports and queries them. Nothing is uploaded.
The only network requests are for the sqlite3 program itself: a signed, content-hashed package from the jsDelivr CDN, fetched once and cached. The counter next to the Run button lists every request that leaves this site.
Results are written only when you save them, into the folder you picked, and existing files are never deleted.
Questions
How are table and column names chosen?
The table is the file name without .csv, with characters other than letters, digits and underscores replaced (sales-2024.csv becomes sales_2024). Columns come from the header row. Use “Show tables and columns” to see them.
Are numbers treated as numbers?
CSV import stores every value as text. SQLite compares and sums text that looks like a number as a number in arithmetic, so sum(qty) works; for sorting or comparisons use CAST(qty AS INTEGER) or CAST(price AS REAL).
Which SQL features are available?
Everything in SQLite 3.54: joins, subqueries, common table expressions, window functions, JSON functions and the math functions. Loadable extensions are not available.
How large can the CSV files be?
The folder is copied into the tab's memory with a 512 MB limit per run. Files of a few hundred megabytes work; very large exports are faster with SQLite on your own machine.
Is my data uploaded?
No. SQLite runs as WebAssembly in your browser tab. The page has no backend, and the request counter on the page shows that nothing but the signed program download leaves the site.
What does the saved CSV look like?
A header row, then one row per result, separated by commas, with quotes where a value needs them and CRLF line endings as RFC 4180 specifies. Spreadsheet programs open it directly.
The software
- program
- SQLite
3.54.0 - license
Public domain- source
- sqlite.org/
- runs on
- WebAssembly (wasm32-wasip1) on the host wasm engine
- delivered as
- a signed, content-addressed package from the NanoVM app catalog (Ed25519 + SHA-256, verified in the browser)
- this page
AGPL-3.0-only OR LicenseRef-UEL· source
Build the same thing into your page
This tool is the <nano-tool> web component from the public NanoVM SDK (@userland-run/nano-sdk/tools), with the built-in csv-sql definition. The same element runs on any page:
<script type="module">
import { defineNanoTool } from "@userland-run/nano-sdk/tools";
defineNanoTool();
</script>
<nano-tool tool="csv-sql" wasm-url="/nano.wasm" terminal url-params></nano-tool>Or headless, with the folder bridge (@userland-run/nano-sdk/folder). Definitions are plain data — presets, form fields and quoted command templates — so you can write one for any catalog app.
import { createNano } from "@userland-run/nano-sdk";
import { mountFolder } from "@userland-run/nano-sdk/folder";
import { runTool } from "@userland-run/nano-sdk/tools";
const nano = await createNano({ image: { wasm: "/nano.wasm" }, ramMB: 512 });
const dir = await showDirectoryPicker({ mode: "readwrite" });
const folder = await mountFolder(nano, dir, { at: "/work" });
// installs sqlite3 from the signed catalog, then runs:
// sqlite3 :memory: '.import --csv regions.csv regions' '.import --csv sales.csv sales' '.mode table' 'SELECT * FROM regions LIMIT 20;'
const r = await runTool(nano, { tool: "csv-sql", preset: "query", folder });
if (r.exitCode === 0) await folder.writeBack(); // new and changed files only; never deletesMore tools
- Image resizer & converterResize, thumbnail and convert a folder of photos to JPEG, WebP or PNG with ImageMagick 7.
- Photo metadata removerStrip GPS location, camera and date metadata from a folder of JPEG, PNG, WebP and HEIC photos.
- PDF toolsMerge, split, optimize and password-protect a folder of PDFs with pdfcpu.