Skip to main content
Version: 0.4 (Latest)

DuckLake Publishing

LakeXpress registers exported Parquet files as tables in a DuckLake catalog without copying data -- the catalog stores metadata (schema, file locations, statistics) while the Parquet files stay in place.

What is DuckLake?​

DuckLake is an open table format and DuckDB extension that stores table metadata (schema, snapshots, file listings, statistics) in a SQL catalog database, while the actual data lives as Parquet files in local or cloud storage. It provides ACID transactions, time travel, and schema evolution on top of plain Parquet -- without requiring a dedicated metadata service.

LakeXpress publishes to DuckLake by creating one table per exported source table and registering the corresponding Parquet files with the catalog, so the data can be queried with standard SQL through DuckDB.

Prerequisites​

1. The ducklake DuckDB extension​

LakeXpress runs INSTALL ducklake and LOAD ducklake automatically before attaching the catalog -- this is a core DuckDB extension (not a community extension), so no manual setup is required as long as the machine running LakeXpress can install it (or already has it cached).

2. A catalog database​

DuckLake stores its metadata in a separate database, which LakeXpress calls the catalog. The catalog credential entry in credentials.json must use one of the supported catalog backends: sqlite, duckdb, postgres, or mysql.

3. An intermediate storage location for the Parquet files​

The exported Parquet files (local directory or cloud storage such as S3, GCS, or Azure) that were produced by the export step -- referenced via --target_storage_id or --output_dir -- are the files registered into the DuckLake catalog.

Catalog Configuration​

The credential entry pointed to by --publish_target is the DuckLake catalog: its ds_type must be one of the four supported catalog backends. LakeXpress detects a DuckLake target automatically when ds_type is sqlite, duckdb, postgres, or mysql (or when the entry explicitly sets "catalog_type": "ducklake").

SQLite catalog​

{
"ducklake_catalog": {
"ds_type": "sqlite",
"info": {
"filepath": "/path/to/ducklake_catalog.sqlite"
}
}
}

DuckDB catalog​

{
"ducklake_catalog": {
"ds_type": "duckdb",
"info": {
"filepath": "/path/to/ducklake_catalog.duckdb"
}
}
}

PostgreSQL catalog​

{
"ducklake_catalog": {
"ds_type": "postgres",
"info": {
"server": "my-postgres-host",
"port": 5432,
"database": "ducklake_meta",
"username": "ducklake_user",
"password": "secret",
"schema": "my_schema"
}
}
}

MySQL catalog​

{
"ducklake_catalog": {
"ds_type": "mysql",
"info": {
"server": "my-mysql-host",
"port": 3306,
"database": "ducklake_meta",
"username": "ducklake_user",
"password": "secret"
}
}
}
FieldBackendsRequiredDescription
ds_typeallYesOne of sqlite, duckdb, postgres, mysql
info.filepathsqlite, duckdbNoPath to the catalog file. Defaults to ducklake_catalog.sqlite / ducklake_catalog.duckdb in the working directory
info.serverpostgres, mysqlNoHost name. Default: localhost
info.portpostgres, mysqlNoPort. Default: 5432 (postgres) / 3306 (mysql)
info.databasepostgres, mysqlNoDatabase name. Default: postgres (postgres backend only)
info.username / info.passwordpostgres, mysqlYesCatalog database credentials
info.schemapostgres onlyNoSchema used for the catalog's own metadata tables (set via search_path). Ignored for mysql and sqlite; duckdb handles schema at query time. Not passed for the other backends

Usage Example​

Ready-to-run commands for DuckLake are in Examples & Recipes: DuckLake.

Querying DuckLake Tables​

Once published, query the tables with DuckDB using the same catalog connection string used for publishing:

INSTALL ducklake;
LOAD ducklake;

ATTACH 'sqlite:/path/to/ducklake_catalog.sqlite' AS lakexpress_lake (TYPE ducklake);

SELECT * FROM lakexpress_lake.my_schema.my_table LIMIT 10;

For a PostgreSQL catalog, the attach string instead looks like:

ATTACH 'postgres:dbname=ducklake_meta host=my-postgres-host port=5432 user=ducklake_user password=secret'
AS lakexpress_lake (TYPE ducklake);

Notes and Limitations​

  • No data copy: DuckLake tables are registered against the existing exported Parquet files (CALL ducklake_add_data_files(...)) -- the data itself is never moved or duplicated into the catalog database.
  • Supported catalog backends: sqlite, duckdb, postgres, and mysql only. Any other ds_type on the --publish_target credential is rejected.
  • Default schema name: if the catalog credential does not set info.schema, LakeXpress logs and tracks the catalog schema as main (used for run tracking metadata; it does not affect the target schema/table naming, which is controlled by --publish_schema_pattern / --publish_table_pattern).
  • Table replacement: if a target table already exists, LakeXpress drops and recreates it before re-registering files (matching the behavior of the other publishers).
  • Column types: when the exported Parquet file is reachable, LakeXpress derives column types directly from the file (DESCRIBE SELECT * FROM read_parquet(...)); otherwise it falls back to mapping the source database types to DuckDB types from the export metadata.
  • Sequential publishing: table creation currently runs sequentially regardless of --n_jobs.

See Also​

Copyright © 2026 Architecture & Performance.