Datapuddle
Powered by DuckDB
Forty million rows. No spinner.
A native Mac client for DuckDB. Drag a multi-gigabyte Parquet onto the icon and it is already scrolling — with the shape of every column drawn into its header.
01 — The grid
Built to be scrolled, not paged.
Cells are read straight from DuckDB's columnar chunks at draw time. Nothing is copied into an intermediate row object, so memory stays flat whether the result is forty rows or forty million.
Scroll end to end at speed and the frame budget holds — the row numbers keep up because nothing is being built to show them.
- Rendering
- Core Text, custom-drawn
- Row objects
- none
- Import step
- none
02 — Column profiles
See the shape before you query it.
Every column header carries a distribution, a null share, and a range. In a year of taxi trips you learn that a flag column is 10% null, and that the pickup timestamps run from 2002 to 2026 — before writing anything.
Profiles arrive after the rows, never before them. The grid does not wait.
- Approximate pass
- from the first window
- Exact pass
- on demand
03 — The inspector
Ask one column for the exact answer.
The header profile is an approximation drawn from the first window of rows, because the grid must not wait for it. Select a column and the inspector runs the exact pass over every row: nulls, distinct count, percentiles, min, max, mean.
Over a year of taxi trips, trip_distance comes back with a median of
1.76 miles, a 99th percentile of 20, and a maximum of 398,608 — a single
row that flattens the histogram and tells you the column needs a filter before it is
worth averaging.
- Rows scanned
- all 41,169,720
- Text columns
- top values, by share
04 — Query plans
Find out where the time went.
EXPLAIN ANALYZE rendered as a tree, with per-operator wall time, its
share of the total, and estimated against actual cardinality. Where the estimate
diverges badly, the node says so.
- Per operator
- time · share · rows
- Bad estimates
- flagged
05 — The editor
It knows the dialect.
Completion for DuckDB's functions, macros and keywords as you type. Highlighting
that understands SUMMARIZE, QUALIFY, PIVOT
and ASOF — words a generic SQL grammar cannot parse.
06 — Connections
Your credentials never touch a config file.
Attach Postgres, SQLite, S3, MotherDuck, or a self-hosted DuckDB server. Every secret goes to the Keychain, keyed by connection — never to a file on disk, never to a log, never to exported history.
After that they just sit in the sidebar, under your files. Expand one to walk its schemas and tables, leave the rest folded away until you want them, and move between a local SQLite file, a Postgres instance and a MotherDuck account without leaving the query you were in the middle of writing.
- Secrets
- Keychain only
- Attached
- as many as you like
07 — History & export
Every query you ran is still here.
Each run is kept with the file it ran against, how long it took, how many rows came back, and whether it failed. Search the lot, then re-run or copy any of them.
When a result is worth keeping, send it straight to Parquet or CSV. DuckDB writes the file itself, so the export is not bounded by what the grid has drawn.
- Kept
- across sessions
- Export
- Parquet · CSV
What's inside
One pinned engine, one binary. Extensions are compiled in — nothing is downloaded at runtime, and the set is identical in both the direct and App Store builds.
- avro
- aws
- azure
- ducklake
- excel
- fts
- core_functions
- httpfs
- iceberg
- icu
- inet
- json
- parquet
- postgres_scanner
- quack
- sqlite_scanner
- vss
17 extensions, statically linked · no runtime INSTALL · no library-validation exemption
Your data never leaves your machine.
This is a product decision, not a setting. There is no backend to send anything to, so there is nothing to opt out of.
-
No accounts
Nothing to sign up for. Open the app and open a file.
-
No telemetry
No analytics, no third-party crash reporter, no phone-home. macOS's own crash reporting applies only if you switched it on yourself.
-
No network you didn't start
The only requests made are the ones your own queries make.
Questions people actually ask
Will it eat my RAM?
No, and the limits are specific rather than reassuring. The engine runs under a 2 GB memory budget and spills to a temporary directory past it, so a file far larger than memory is a slower query, not a crash. The grid holds only the rows near your viewport — result rows are never turned into objects at all, which is an architectural rule rather than an optimisation.
The clips on this page are a 41,169,720-row Parquet, scanning 630 MB, on a laptop.
How large a file can it open?
Larger than your memory. The practical ceiling is disk — both for the file and for the temporary directory the engine spills into. There is no row limit and no truncation: the grid shows the whole result, not its first page.
Is it a subscription?
No. Free to download and fully functional for a trial period, then a one-time purchase to keep. No account either way, and nothing to cancel.
Does it work offline?
Entirely, for local files. Every DuckDB extension it uses is compiled into the binary, so there is no download on first run and no licence check over the network. It reaches out only for a remote source you configured.
Is this the DuckDB UI extension?
No. That one is a web app served from localhost,
started from a terminal, which stops when the DuckDB process does. This is a
Mac app: Finder integration, multiple windows, full keyboard control, and
nothing to launch first. DuckDB is the engine inside it.
Can I connect to Postgres, MotherDuck or S3?
Yes — plus SQLite and a self-hosted server over DuckDB's Quack protocol. Credentials go to the macOS Keychain, per connection, never to a settings file. MySQL is not supported: its DuckDB extension cannot be statically linked, and this app links everything it ships.