Online viewers
Three pages that open a data file in a browser tab and let you query it. No account, nothing installed, and the file never leaves the tab.
- Parquet Viewer —
.parquet - JSONL Viewer —
.jsonl,.ndjson - SQLite Viewer —
.db,.sqlite,.sqlite3
All three behave the same way, so this one page is the reference for all of them.
Open a file
- Go to the viewer for your format.
- Drag the file onto the page, or click Choose files.
- The rows appear straight away, and the SQL editor is one tab away.
Nothing is uploaded. The file is read inside the browser tab, so there is no server copy to worry about and closing the tab leaves nothing behind — which is what makes it safe to open a file you were sent rather than one you own.
You can look and query, but not change: the viewers run SELECT only. The file you opened is the
file you still have.
Opening several files at once
The Parquet and JSONL viewers hold several files of their format open together. Each file becomes a named view, so the SQL reads like SQL rather than like a path:
SELECT c.country, count(*) AS orders, round(sum(o.amount), 2) AS total
FROM orders o
JOIN customers c USING (customer_id)
GROUP BY 1
ORDER BY total DESC
Stacking files that should have been one file is the same idea with a set operation. BY NAME
matches columns by name instead of position, which is what saves you when the writer added a column
halfway through the quarter:
SELECT * FROM january
UNION ALL BY NAME
SELECT * FROM february
Where the view names come from
The name is derived from the filename, because a filename is usually not a SQL identifier:
- everything that is not a letter, a digit or
_becomes_; - a name that would start with a digit gets an
f_in front of it; - a second file whose name collides gets
_2, then_3.
So 2026 orders-final.parquet is queried as f_2026_orders_final. You never have to work this out —
the sidebar shows the name each file was given, and clicking a file writes the query for you.
Dropping the same file twice does not open it twice: the copy already open is selected instead. Two different files that happen to share a name both open, under names that differ.
The SQLite viewer opens one database at a time — a .db file already contains many tables, and they
join without any of this.
Two tabs: browsing and querying
The right-hand pane has a Data tab and a SQL tab, and they do not share state.
- Data previews whatever the sidebar has selected — a file in the Parquet and JSONL viewers, a table or view in the SQLite one. Clicking in the tree brings this tab forward and shows the rows.
- SQL holds the editor and its result. Clicking a file never touches it, so a query you are part-way through writing cannot be destroyed by a click in the tree.
Switching tabs re-runs nothing; both grids keep their sort, column widths and scroll position.
Press Ctrl+Enter (⌘+Enter) in the editor to run the query.
The file information panel
Under the file tree, a panel describes whatever is selected. It changes with the selection rather than describing the workspace, because with several files open a single header would be describing only one of them.
| Viewer | What the panel shows |
|---|---|
| Parquet | Rows, row groups, compression codec, uncompressed size, and the writer that produced the file |
| JSON Lines | The per-line validation result: how many lines are valid data, and how many failed to parse |
| SQLite | Rows, indexes, page size, page count, unused pages, text encoding, user version, application id, the SQLite version that wrote it, and a PRAGMA integrity_check result |
For Parquet, each column in the tree expands to the statistics the file carries for it — minimum,
maximum, null count and share, compressed size on disk and uncompressed size. Those numbers belong
to the file, which is why they appear under the file and not next to the result of a query: after a
GROUP BY the minimum of a source column describes the file, not the rows on screen.
Why JSON Lines needs its own viewer
JSON Lines is one JSON value per line, which is what makes it streamable and also what makes a single bad line break a whole-file parse. So validation is per line: you get the count of valid data lines, the count and position of the ones that failed, and column types inferred across the whole file rather than guessed from the first record — nested objects included, and keys a JSON viewer usually mangles, like ones with dots or spaces in them.
Binary and media values
This applies wherever the data actually carries bytes: BLOB columns in SQLite, and BLOB
columns in Parquet. JSON Lines has no binary type, so the case does not arise there — a
base64 string in a JSONL file is text, and is shown as text.
A BLOB is not printed as bytes. The cell shows its size and what the bytes turn out to be, and
images small enough to be cheap get a thumbnail:
The kind is worked out from the value itself, not from a column name or a file extension, so it is right even when the database says nothing about what it stores:
| What is in the blob | What you get |
|---|---|
| PNG, JPEG, GIF, WebP, BMP, ICO, AVIF, SVG | the picture |
| MP4, MOV, WebM, Matroska | a player, with controls |
| MP3, WAV, Ogg, FLAC | a player, with controls |
| TIFF, HEIC | the name and size — no browser can display these, so download it instead |
| text | the text |
| anything else | a hex dump of the first kilobyte |
Right-click a cell for Preview value and Download value. The download carries the detected
media type, so a blob that is a PNG arrives as a .png file.
Two limits are deliberate, and both exist so that a large value cannot make the grid expensive:
- thumbnails only for images under 512 KB. A larger image shows its size and opens in full when you ask for the preview;
- nothing is decoded while rows render. The preview builds its object URL when you open it and releases it when you close it.
A blob of zero length reads BLOB · empty, which is not the same as NULL and is not shown as one.
Exporting the result
The export button writes the whole result set, not the page of rows the grid happens to show, and it belongs to the tab you are on: on Data it exports the file you are previewing, on SQL the result of your query.
| Viewer | Formats |
|---|---|
| Parquet, JSON Lines | CSV, JSON, Parquet — written by DuckDB itself, so types survive the round trip |
| SQLite | CSV and JSON |
Binary values are written as hex in CSV and JSON. To get the bytes themselves, use Download value on the cell.
Limits
- Read-only.
SELECTandWITH … SELECTonly — noINSERT,UPDATE,CREATEorCOPY. - A file has to exist already. The viewers open data; they do not generate or edit it.
- 10,000 rows per query. Results are capped, so a
SELECT *over a huge file stays responsive; aggregate in SQL rather than scrolling. - One format at a time. Several Parquet files together, or several JSONL files together — but not Parquet joined to JSONL, and not a file joined to a database.
- The browser's memory is the ceiling. There is no fixed file-size limit; what a tab can hold depends on the machine, the format and the query.
Querying across different sources is a DBConvert Streams feature rather than a browser one — see Federated queries.
When a file will not open
- Wrong page for the file. Each viewer checks the signature and says which of the three pages the file belongs to, rather than failing vaguely. Opening a Parquet file in the JSONL viewer is a one-click correction.
- A JSONL file with malformed lines is reported with the count before anything is queried. Other files already open stay open.
- A SQLite database marked as WAL but without its
-walsidecar is still a valid, self-contained snapshot when its changes were checkpointed, so it is read as one. That affects only the private copy in the tab; your file is not modified.