Cloud Parts

Small lakehouse on DuckLake

DuckDB writes and queries tables whose catalog lives in PostgreSQL and whose data sits as Parquet on S3.

Fits: One team, gigabytes to a few terabytes4 technologies
Live model
What you’re watchingA nightly load writes new rows: DuckLake commits the snapshot to PostgreSQL and the data to S3 as Parquet. Analysts’ queries look up the current files in the catalog and read them from S3.

Click any box to open its page. Open it in the playground to rewire it, change the traffic or take parts down.

A lakehouse doesn’t need a fleet of servers. Here a nightly job and a handful of analysts all use DuckDB, an engine that runs inside their own process, and share one set of tables through DuckLake. The catalog that says which Parquet files make up each table, and every past snapshot, is just a few tables in a PostgreSQL database. The data is plain Parquet in an S3 bucket. There’s nothing else to run.

How it flows

  1. 1

    Load runs inside DuckDB

    The nightly job is a script that starts DuckDB, runs ATTACH 'ducklake:postgres:…', and inserts the day’s CSV exports. No cluster starts up; the work happens in the job’s own process.

    Nightly loadDuckDB
  2. 2

    Data lands as Parquet

    DuckLake writes the new rows as Parquet files under the bucket’s data path. Existing files are never changed, so a half-finished load can’t corrupt what readers see.

  3. 3

    One transaction commits the snapshot

    The list of new files, their statistics and a new snapshot id go into the catalog tables in PostgreSQL in a single transaction. The moment it commits, every reader sees the new data; until then, nobody does.

  4. 4

    Queries ask the catalog, then read files

    An analyst’s DuckDB asks PostgreSQL which files belong to the current snapshot and uses their min/max statistics to skip files that can’t match. It then reads only the Parquet it needs from S3. AT (VERSION => n) reads an older snapshot instead.

Why this shape works

  • Almost nothing to operate: one PostgreSQL database and a bucket, both of which you may already run
  • Commits are database transactions, so loads that touch several tables are atomic
  • Readers scale out for free: each analyst’s laptop or notebook is its own engine
  • The data is ordinary Parquet, so other tools can read the files, and tables can be copied out to Iceberg later

Where it strains

  • Every query and commit touches PostgreSQL; size and back it up like the critical system it now is
  • Each DuckDB runs on one machine, so a single query is limited to what that machine can scan
  • Few engines besides DuckDB read DuckLake today; if Spark or Trino must join in, Iceberg is the safer choice
  • Many tiny loads still make many small files; use data inlining or run compaction regularly

Common swaps

  • Everything on one machine? Keep the catalog in SQLite (or a DuckDB file) next to the data, and skip PostgreSQL entirely.

  • Avoid egress fees or stay on your own hardware by pointing the data path at another S3-compatible store.

  • Need many different engines on the same tables? Build the same shape on Iceberg with a REST catalog instead.

Built from

Architectures with parts in common

Sources

Improve this page on GitHub