S3 Tables location
S3 Tables is AWS's managed Apache Iceberg table storage built directly into S3. Use this location type to store Depot Dataset data in an S3 Tables bucket. Athena, DuckDB and Spark reach its datasets directly: see Iceberg interop case studies.
The account's bootstrap must be deployed with s3TablesIceberg: true. Without it the environment deploy fails: the stack imports SDP-Bootstrap-S3TablesLfGrantCrRoleArn, an export that only this flag creates.
Configuration properties
| Property | Required | Default | Description |
|---|---|---|---|
name | yes | — | A name or alias for this location. Must be unique within the environment. |
tableBucketName | no | sdp-${envId}-data | Override the default table bucket name. Strongly discouraged — AWS allows only 10 table buckets per region per account. Use only if you must point at a pre-existing bucket or share a bucket across environments. |
tableBucketArn | no | — | ARN of an externally-provisioned S3 Tables bucket. When set, Depot does not create or manage the bucket lifecycle — it only creates its own Catalog Integration and Linked Catalog Database against the external bucket. Mutually exclusive with tableBucketName. |
removalPolicy | no | RETAIN | Removal policy for the bucket that backs this location. One of DESTROY, RETAIN, SNAPSHOT. Use DESTROY for non-production. |
icebergVersion | no | 2 | Iceberg table format version to use for tables created under this location. Accepts 2 or 3. Use 3 only if all consumers (Snowflake, Athena, etc.) support Iceberg v3 in your environment — consult the Iceberg compatibility matrix to verify reader support before opting in. Per-table override: snowflake.iceberg.icebergVersion schema extension. |
deleteMode | no | MERGE_ON_READ | Row-level delete strategy for Iceberg tables. MERGE_ON_READ writes delete files and lets readers reconcile. COPY_ON_WRITE rewrites data files on every delete or update. Per-table override: snowflake.iceberg.deleteMode schema extension. |
Example
import { Location } from '@stage-tech/depot-cdk';
new Location.S3Tables(this, 'MyDataLake', {
environment,
name: 'my-data-lake',
// icebergVersion: 3,
// deleteMode: 'COPY_ON_WRITE',
});
Supported field types
| Field type | Stored as |
|---|---|
| Every scalar | One typed column |
array and set of any scalar or enum | ARRAY(X); binary and secret elements are base64 VARCHAR |
ref in an array or set | ARRAY(OBJECT(...)) holding the id, plus version when the ref is versioned |
struct at any depth | Typed columns, or a typed OBJECT(...) for layout: structured |
map of scalars, refs, structs, arrays or maps | MAP(VARCHAR, X) |
| Array of arrays, maps or structs | Nested ARRAY, MAP and OBJECT types, at any depth |
any | JSON text in VARCHAR on Iceberg v2; VARIANT on Iceberg v3 |
Nested struct keys are stored lower_snake. Map keys are stored as written.
x in <array of arrays> is refused; x in r for any r of <array of arrays> works. On Iceberg v3, Snowflake rejects a NULL element in an array of any.
Refused at planning
A migration with one of these changes fails when it is planned:
- switching a struct between
layout: flattenedandlayout: structured; - switching a property between an array and an array of arrays;
- retyping a value out of
any, top-level or nested; - turning an unversioned
refinside an array, set, map or structured struct into a versioned one: stored refs carry no version and would read back as null.
External bucket mode
Use tableBucketArn to point Depot at a bucket provisioned and managed outside of Depot (e.g. shared infrastructure or a cross-team bucket).
In external mode Depot:
- does not create or delete the
AWS::S3Tables::TableBucketresource - creates its own Snowflake Catalog Integration and Linked Catalog Database against the external bucket
- does not manage the bucket or namespace lifecycle
new Location.S3Tables(this, 'ExternalLake', {
environment,
name: 'external-lake',
tableBucketArn: 'arn:aws:s3tables:eu-west-1:111122223333:bucket/shared-bucket',
});
Dataset-level namespace management is configured separately on the dataset's s3tables extension. Set namespaceManagement: 'EXTERNAL' there if the namespace itself is also externally managed.
Cross-account external buckets
When tableBucketArn belongs to a different AWS account, Depot cannot automate Lake Formation setup — the owning account must configure the following manually before Snowflake queries will succeed:
-
Account-level prerequisites (once per account): an account bootstrapped by Depot with
s3TablesIceberg: truealready has them. In any other account, registerarn:aws:s3tables:{region}:{account}:bucket/*as a Lake Formation data location (WithFederation: true) using a role that trustslakeformation.amazonaws.comwithsts:AssumeRole. Create a Glue federated catalog (s3tablescatalog) pointing to that wildcard ARN. -
Catalog-level grant (once per bucket): grant
ALLon the default Glue catalog and on the S3 Tables sub-catalog ({ownerAccountId}:s3tablescatalog/{bucketName}) to the Snowflake IAM role. -
Namespace-level grant (once per dataset): grant
ALLonDatabase { CatalogId: "{ownerAccountId}:s3tablescatalog/{bucketName}", Name: "{namespaceName}" }to the Snowflake IAM role.
The Snowflake IAM role must also have lakeformation:GetDataAccess in its IAM policy. Cross-account LF grants may additionally require AWS Resource Access Manager (RAM) sharing — consult the AWS Lake Formation cross-account documentation.
Before Depot 10.7.0, depot-cdk had a Glue-catalog Location.Iceberg location and an Executor.EmrServerless executor that ran Spark on it. 10.7.0 removed both; S3 Tables replaces them. depot-cdk rejects them at the type level, so upgrading from 10.6.0 may require removing them from the CDK code.