How do I migrate Delta tables to Iceberg?
Summary
- There are three documented routes: a CTAS copy into a new Iceberg table, the
snapshotDeltaLakeTableaction from Apache Iceberg'siceberg-delta-lakemodule (Iceberg metadata over the existing Parquet files), or keeping the table in Delta Lake with UniForm so Iceberg clients can read it. - A full copy is isolated from the source but rewrites every data file, and the new table doesn't inherit the source's partitioning, so declare it with
PARTITIONED BY. - A metadata-only snapshot reuses the Delta data files, so it breaks if the Delta table deletes them. Iceberg's
snapshotandmigrateSpark procedures are documented for Hive or Spark tables, not Delta. - On Databricks, Iceberg reads (UniForm) let Iceberg clients read Delta tables through Unity Catalog without rewriting files, and managed Iceberg tables are created with
USING iceberg.
How do I migrate Delta tables to Iceberg?
Pick the route by what you need at the end. For an independent Iceberg table, copy the data with a CTAS into an Iceberg catalog. To avoid rewriting data, Apache Iceberg's iceberg-delta-lake module can snapshot a Delta table into a new Iceberg table that points at the same Parquet files. If Iceberg engines only need to read, you may not need to migrate at all: Delta Lake's Universal Format (UniForm) generates Iceberg metadata for a Delta table. Iceberg's snapshot and migrate Spark procedures are documented for Hive or Spark tables, and Iceberg provides a separate action for Delta Lake.
Which migration approach fits?
| Approach | What it does | Trade-off |
|---|---|---|
Full data migration (CTAS, INSERT, writeTo(...).create()) |
Copies the current data into a new Iceberg table | Fully isolated from the source, at the cost of rewriting every file; partitioning must be declared again |
Snapshot (snapshotDeltaLakeTable) |
Converts the Delta transactions into a new Iceberg table "with the same schema and partitioning", reusing the data files | No rewrite, but the Iceberg table doesn't own its files; expire_snapshots is prohibited and deletes on the Delta side break it |
| Keep Delta, enable UniForm | Delta generates Iceberg metadata asynchronously after write transactions | Iceberg clients can only read; no deletion vectors |
How do I copy a Delta table into a new Iceberg table?
Configure an Iceberg catalog alongside Delta's session catalog, for example spark.sql.catalog.ice set to org.apache.iceberg.spark.SparkCatalog with its type and connection settings. Then run a CTAS that reads the Delta table by path. Iceberg runs CTAS as an atomic operation with a SparkCatalog.
CREATE TABLE ice.db.events
USING iceberg
PARTITIONED BY (event_date)
AS SELECT * FROM delta.`/data/delta/events`;
-- Compare counts before switching readers and writers
SELECT count(*) FROM ice.db.events;
SELECT count(*) FROM delta.`/data/delta/events`;
In PySpark, df.writeTo("ice.db.events").create() is the DataFrame equivalent of CREATE TABLE AS SELECT. Iceberg doesn't recommend the v1 df.write API and warns that format("iceberg") loads an isolated table reference that will not automatically refresh tables used by queries. The copy starts its own Iceberg history.
How do I convert without rewriting data files?
Use the iceberg-delta-lake module. It isn't bundled with the Spark or Flink runtimes; the minimum dependencies are iceberg-delta-lake, delta-standalone-0.6.0 and delta-storage-2.2.0. It's built and tested with Delta Standalone 0.6.0 and supports Delta tables with minReaderVersion 1 and minWriterVersion 2.
DeltaLakeToIcebergMigrationActionsProvider.defaultActions()
.snapshotDeltaLakeTable("s3://my-bucket/delta-table")
.as(TableIdentifier.of("my_db", "my_table"))
.icebergCatalog(icebergCatalog)
.tableLocation("s3://my-bucket/iceberg-table")
.deltaLakeConfiguration(hadoopConf)
.execute();
Here icebergCatalog is an Iceberg Catalog and hadoopConf a Hadoop Configuration that can read the Delta table. The original Delta table remains unchanged. DELETE statements on it remove data files the snapshot can then no longer read, and picking up later Delta commits relies on the Add Transaction action, which the Iceberg docs say is still under development.
What if Iceberg engines only need to read the table?
Enable UniForm. It "takes advantage of the fact that Delta Lake, Iceberg, and Hudi all consist of Parquet data files and a metadata layer", so a single copy of the data files serves both formats. In open-source Delta Lake it needs column mapping, minReaderVersion 2 or higher and minWriterVersion 7 or higher, writes from Delta Lake 3.1 or above, and Hive Metastore as the catalog. Enabling it on an existing table with ALTER TABLE needs Delta 3.3 or above.
ALTER TABLE events SET TBLPROPERTIES(
'delta.enableIcebergCompatV2' = 'true',
'delta.universalFormat.enabledFormats' = 'iceberg');
-- If the table has deletion vectors enabled, use REORG instead
REORG TABLE events APPLY (UPGRADE UNIFORM(ICEBERG_COMPAT_VERSION = 2));
How Databricks approaches Delta-to-Iceberg interoperability
On Databricks, the UniForm route is called Iceberg reads (UniForm). Available in Databricks Runtime 14.3 LTS and above, it configures Delta Lake tables "to automatically generate Iceberg metadata, so Iceberg clients can read Delta Lake data without rewriting files". The table must be registered to Unity Catalog with column mapping enabled, and you can't enable deletion vectors on it. Unity Catalog can act as the Iceberg catalog for external clients, whose access is read-only. For a native Iceberg table, create a Unity Catalog managed Iceberg table with USING iceberg on Databricks Runtime 16.4 LTS and above; external Iceberg engines can read and write it through the Iceberg REST Catalog API.
FAQs
Can I convert a Delta table to Iceberg without copying data?
Yes. snapshotDeltaLakeTable adds the existing data files to a new Iceberg table's metadata, and UniForm keeps the table in Delta while generating Iceberg metadata over the same files. With the snapshot, the Iceberg table depends on the Delta table keeping those files.
Does the Iceberg table keep my Delta history?
It depends on the route. For Delta Lake sources, the Iceberg docs say "all available transactions will be committed to the new Iceberg table as transactions in order". A CTAS copy starts fresh. With UniForm, Delta and Iceberg versions don't align by commit timestamp or version ID.
Can Iceberg engines write to a UniForm table?
No. Iceberg clients can only read from UniForm, and the Delta docs warn that an external writer "may destroy your Delta table and cause data loss".
The information provided herein is for general informational purposes only and may not reflect the most current product capabilities or configurations.