Setup
- Open Settings → Lake and choose Add Postgres connection.
- Paste a connection string to fill the fields automatically, or enter them by hand:
The dialog generates the SQL for a read-only user if you want to create one - copy it and run it against your database before saving.
Querying live
Tables are reachable asconnection_name.schema.table:
A Postgres table selects DuckDB. DuckDB is the only engine that attaches external connections, so the query router routes any query naming a connection table here before it considers input size - leave
engine on auto. Asking for Bloom, Polars, or Spark on one of these queries returns an engine capability error rather than rerouting silently.Importing into Iceberg
For anything larger than an ad hoc read, import the table. The import runs as a Spark JDBC read and lands the data as an Iceberg table in your lake, where every engine can reach it. The import plans itself from Postgres catalog metadata:- Partition count follows table size.
- Partition ranges come from the integer primary key, balanced by histogram, or from physical
ctidchunks when there is no suitable key. - Every partition reads from one exported MVCC snapshot, so the copy is consistent even against a live, changing database.
oleander.default.<table> - the sanitized source table name, with no connection prefix. OVERWRITE replaces it, APPEND adds to it.
An import does not return rows. It submits a job and returns a run_id you can monitor like any other run, and once it completes you can sample the destination with a normal query.
Table syncing
A one-off import gives you a snapshot. Put the same import on a schedule and the Iceberg copy tracks the source instead.Scheduled syncs are incremental. After the first full import, each run picks up new and changed rows only rather than recopying the table, so a sync over a large table costs a fraction of the initial import.
connection.source_table → destination_table pair, listed under Scheduled syncs in Settings → Lake with its cadence and next run time, where it can be paused or removed.
The same schedules also show up as Transfers in the lake’s left panel, under the Schedules tab next to scheduled queries. Each row shows the source and destination tables, a health indicator from the last run, and the next run time; expand it for run history, or pause/delete it from there instead of Settings. Tables with an active sync are marked with a small lightning-bolt icon in the catalog tree.
A one-time import doesn’t create a schedule, so it never appears under Transfers - only recurring syncs do. Track a one-time import’s progress in observability instead.
From an agent
Two tools cover Postgres over MCP:
For ad hoc reads of live data an agent uses
query_run against connection.schema.table instead.