# Iceberg table properties Iceberg tables include a key-value map of table properties in their metadata. The initial map of table properties is set at table creation, and can be modified subsequently using `ALTER TABLE ... SET TBLPROPERTIES`. The Iceberg specification reserves a set of key properties and Foundry also provides a set of keys that are used to track Foundry-specific metadata, such as table RIDs. ## Foundry-specific properties Foundry-specific properties include: | Property | Description | User edits | |---|---|---| | **`created-at`** | Table creation timestamp (cross-catalog convention) | ✅ Allowed | | **`foundry.branch.*`** | Track [branch-scoped schema, partition spec, and sort order](../branching/index.md) | ❌ Disallowed | | **`foundry.rid`** | The table's RID | ❌ Disallowed | | **`foundry.table-version`** | Internal catalog marker | ❌ Disallowed | ## Iceberg specification properties The Iceberg specification also reserves a set of core [Iceberg table properties ↗](https://iceberg.apache.org/docs/latest/configuration/#table-properties). Foundry's Iceberg REST catalog includes the following constraints on certain core Iceberg table properties: | Property | Foundry default value | User edits | |---|---|---| | **`encryption.*`** | Set as part of [Iceberg table encryption](../storage/index.md#encryption-settings) if enabled | ❌ Disallowed | | **`format-version`** | See [format version defaults](../versions/index.md) | ✅ Allowed | | **`history.expire.max-snapshot-age-ms`** | `2592000000` (30 days) | ✅ Allowed | | **`write.metadata.delete-after-commit.enabled`** | `false` | ❌ Disallowed | | **`write.metadata.previous-versions-max`** | `1` | ✅ Allowed | | **`write.object-storage.enabled`** | `true` | ❌ Disallowed | | **`write.object-storage.partitioned-paths`** | `false` | ❌ Disallowed | | **`write.data.path`** | | ❌ Disallowed | | **`write.folder-storage.path`** | | ❌ Disallowed | | **`write.location-provider.impl`** | | ❌ Disallowed | | **`write.metadata.path`** | | ❌ Disallowed | | **`write.object-storage.path`** | | ❌ Disallowed | Where Foundry provides a default value, it takes precedence over the open source Iceberg specification default. Any property not explicitly set uses the Iceberg specification default value. :::callout{theme="success"} The default settings applied by Foundry are subject to change. To guarantee specific property values, make sure to explicitly set those on your table as described below. ::: ## Set specific table properties in transforms You can set specific table properties manually, for example, by running an `ALTER TABLE` statement in the Iceberg maintenance page, or by specifying properties in your transform code. Below is an example code snippet setting table properties in transforms: ```python tab="Polars" import polars as pl from transforms.api import transform from transforms.tables import IcebergOutput, TableOutput @transform.using(output=TableOutput("/path/table")) def compute(output: IcebergOutput) -> None: df_custom = pl.DataFrame({"phrase": ["Hello", "World"]}) output.write_table(df_custom) tbl = output.iceberg().table() with tbl.transaction() as txn: txn.set_properties({ "write.delete.mode": "merge-on-read", "write.update.mode": "merge-on-read", "write.merge.mode": "merge-on-read", "history.expire.max-snapshot-age-ms": "0", }) ``` ```python tab="PySpark" from transforms.api import TransformContext from transforms.api import transform from transforms.tables import ( TableOutput, TableTransformOutput, ) @transform( output=TableOutput("/path/table") ) def compute(ctx: TransformContext, output: TableTransformOutput): spark = ctx.spark_session df_custom = spark.createDataFrame([["Hello"], ["World"]], schema=["phrase"]) output.write_dataframe(df_custom) identifier = output.identifier spark.sql(f""" ALTER TABLE {identifier} SET TBLPROPERTIES ( "write.delete.mode": "merge-on-read", "write.update.mode": "merge-on-read", "write.merge.mode": "merge-on-read", 'history.expire.max-snapshot-age-ms' = '0' ) """) ``` :::callout{theme="warning"} Set table properties only after writing the output table. This ensures that the table exists before you set properties on it, and prevents the replace operation performed by Spark's `write_dataframe` from overwriting your preferred property values with the defaults. :::