DuckDB 61,228 reaches the lakehouse through two autoloading extensions. The iceberg extension (https://github.com/duckdb/duckdb-iceberg 444 ) attaches a REST catalog as a database, with reads and CREATE, INSERT, UPDATE and DELETE committed through the catalog; the delta extension (https://github.com/duckdb/duckdb-delta 231 ), built on the Delta project's Rust Delta Kernel, reads Delta tables by path:
-- DuckDB as a lakehouse client: Iceberg through the REST catalog, Delta Lake by path.
SET TimeZone = 'UTC';
CREATE SECRET (TYPE s3, KEY_ID 'booknest-admin', SECRET 'booknest-secret-2026',
ENDPOINT 'localhost:31900', URL_STYLE 'path', USE_SSL false, REGION 'us-east-1');
ATTACH 'warehouse' AS lake (TYPE iceberg, ENDPOINT 'http://localhost:31181',
AUTHORIZATION_TYPE 'none');
.mode column
SELECT channel, sum(orders) AS orders, sum(gross) AS gross FROM lake.booknest.daily_sales
WHERE order_date >= DATE '2026-01-01' GROUP BY channel ORDER BY gross DESC;
CREATE TABLE lake.booknest.duck_scratch AS SELECT book_id, price FROM lake.booknest.books;
UPDATE lake.booknest.duck_scratch SET price = price - 1 WHERE book_id = 1;
DROP TABLE lake.booknest.duck_scratch;
SELECT sku, title, price FROM delta_scan('s3://warehouse/delta/catalog') ORDER BY sku LIMIT 2;... channel orders gross ------- ------ --------- ios 14917 484632.10 ... sku title price ------- ------------------------ ----- BN-0001 The Quiet Harbor 14.99 ...
The UPDATE committed an overwrite snapshot, so three engines now commit to one catalog. Two pitfalls: DROP TABLE here leaves the files in MinIO 30,943 (the fixture does not purge; mc rm -r cleaned up), and iceberg_scan() on a bare path needs the metadata file's path or SET unsafe_enable_version_guessing = true, which may read a rolled-back version. With no server to run, DuckDB suits notebooks, CI checks and small services, within one machine's limits.