Zug Zug.
Reference

Architecture

The three stores, the request path, and where state lives.

Zug Zug reads and writes three separate stores. Keeping them separate is the central design decision — each has a different owner and durability need.

The three stores

StoreTechnologyOwnerHolds
WarehouseYours (MotherDuck/DuckDB, Snowflake)Yours — read-only to Zug ZugThe columns Zug Zug scans for distinct source values.
Record storePostgres (default) or MotherDuckZug ZugThe published dim_<x> / map_<x> tables — approved records and mappings, versioned.
App statePostgres (zugzug_app schema)Zug Zug — back this upDrafts, audit log, users, sessions, table versions, the outbound-event queue.

Request path

The browser only talks to the Bun API (/api, /ws). The API talks to Postgres and — when attached — a local DuckDB engine that ATTACHes your warehouse and the record store, so it can query across them.

  • Frontend (app/): React + Vite + Tailwind, static assets served by nginx.
  • Backend (server/): a Bun HTTP server, path-routed under /api. Background work (scans, webhook dispatch, retention sweeps) runs on an in-process scheduler.

What leaves your warehouse

The read path is deliberately narrow. For each source you register, Zug Zug runs SELECT DISTINCT <column> (with frequency counts) and copies only those distinct values into its Postgres, so the team can map them in Review. It never reads other columns, never reads full rows, and never writes back unless you turn on a writable adapter. The distinct values of the columns you register are the only warehouse data that ever lands in Zug Zug — a good property to keep in mind when you scope the read-only credential.

Publish model

Editing is instant on the working copy; publish folds drafts and record edits into a numbered version and materializes dim_<x> / map_<x>. See Publishing.

On this page