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.

Apple silicon · macOS 14+ · free trial, then a one-time purchase

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
The sidebar with three connections attached: a MotherDuck account expanded to its schemas, a SQLite file and a Postgres database folded away beneath it

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.

DuckDB 1.5.5 Pinned deliberately and upgraded deliberately. The version you see here is the version that ships.

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.

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.

More in support →

Open a file. That's the whole setup.

Apple silicon · macOS 14 or later · free trial, then a one-time purchase