Skip to content
Three stacked strata forming a ridge, the Moraine markThree stacked strata forming a ridge, the Moraine mark

Moraine

Run DuckLake entirely in object storage, no server required.

DuckLake stores table data as Parquet files in object storage and hosts its catalog in a SQL database: SQLite, Postgres, or DuckDB (served over Quack). The database layer provides transactional consistency and ACID guarantees, but requires hosting an additional server.

Moraine removes the need for a separate catalog database. Instead, it serves the catalog from SlateDB, an embedded transactional key-value store that also lives in object storage. That means that the catalog resides in the same bucket as the data files. In addition, Moraine is the only DuckLake extension that offers DuckDB native indexes for faster querying.

LOAD 'moraine.v2.0.0.linux_amd64.duckdb_extension';

CREATE SECRET aws_secret (TYPE s3, KEY_ID '…', SECRET '…', REGION 'us-west-2');
ATTACH 'ducklake:moraine:s3://bucket/lake' AS lake
  (DATA_PATH 's3://bucket/lake-data/', READ_WRITE);

CREATE TABLE lake.events (id BIGINT, payload VARCHAR);
INSERT INTO lake.events VALUES (1, 'hello, bucket'), (2, 'hello again');
SELECT * FROM lake.events;

CREATE UNIQUE INDEX events_by_id ON lake.events (id);
SELECT payload FROM lake.events WHERE id = 2;
  • No catalog server: No catalog server to deploy or monitor. The only permanent resource is a storage bucket.
  • Nothing to pay for while idle: An idle lake costs only storage, no compute or database hosting fees.
  • Bucket durability: The catalog is objects in the bucket, so it inherits the bucket’s durability, replication, and versioning. A copy taken while no writer is attached is a complete lake; see Backups and copies.
  • Indexed lookups: Ordered indexes over table columns, created with CREATE INDEX and maintained in the same commit as the rows, so a query by key probes the index instead of scanning every file; see Index a column.
  • Sub-5 ms commits. A commit is durable once one write-ahead-log PUT lands: 50 to 100 ms on S3 Standard, 5 to 10 ms with the log on S3 Express One Zone via META_WAL_PATH.
  • Many independent writer processes. One process writes; the rest attach READ_ONLY. See one writer, many readers.
  • INSTALL moraine FROM community. The listing is in progress. Until then, signed builds come from Moraine’s own extension repository, which takes one CREATE EXTENSION REPOSITORY to register.

Identical DuckLake workloads through the same DuckDB CLI, only the catalog swapped. Local disk, loopback Postgres 16, medians of three runs on an 8-vCPU x86-64 VM:

Moraine DuckDB file Postgres
attach 8 ms 19 ms 113 ms
create table and insert 100,000 rows 94 ms 102 ms 124 ms
20 single-row commits, one connection 254 ms 218 ms 135 ms
128 single-row commits over 8 connections 417 ms 1.76 s 1.77 s
128 single-row commits over 16 connections 461 ms 2.85 s 2.94 s

Serial commits pay a write-ahead-log flush each, where a local Postgres is faster. Overlapping commits can share one flush, giving Moraine more competitive performance. On S3, each flush is one PUT round trip, about 30 ms same-region. For more details, see Benchmarks.

Moraine is under active development and in production use at contour.app. All DuckLake SQL, including CREATE, INSERT, UPDATE, DELETE, time travel, and maintenance, runs against Moraine.

Dual-licensed under MIT or Apache-2.0.

More details

  • Getting started: how to install the extension and attach a lake.
  • Configuration: attach options, environment variables, and DuckDB functions.
  • Operating manual: retention, maintenance, encryption, backups, and upgrades.
  • Comparison: Moraine alongside DuckDB, Postgres, Quack, and Iceberg-style catalogs.
  • Design: key design decisions and rationale.
  • Benchmarks: performance benchmarks against other DuckLake catalogs.
  • Releases: changelog, extension downloads, and the DuckDB compatibility table.
  • Roadmap: what’s next for Moraine.