Back to changelog
Improvement
3 minute read

Snowflake: Warehouse, Table, Stage, and Function Attributes

Atlas now manages multi-cluster and query acceleration settings on warehouses, file and refresh settings on external tables, storage and versioning settings on Iceberg tables, a warehouse on dynamic tables, credentials on stages, and volatility on functions.

A set of Snowflake object properties that inspection previously skipped is now part of the schema: they are read from the account, compared, and planned with the statements Snowflake accepts for each one.

Warehouses

A warehouse now takes its multi-cluster layout, its query acceleration settings, and the session parameters it runs statements under:

warehouse "WH" {  size                                = XSMALL  min_cluster_count                   = 1  max_cluster_count                   = 3  scaling_policy                      = ECONOMY  enable_query_acceleration           = true  query_acceleration_max_scale_factor = 4  max_concurrency_level               = 8  statement_timeout_in_seconds        = 3600  statement_queued_timeout_in_seconds = 600}

Every one of them is optional, and a desired state that names none of them adopts the values the warehouse already has, so adding a warehouse to your schema never plans a change you did not ask for. scaling_policy is STANDARD or ECONOMY.

Iceberg, External, and Dynamic Tables

An Iceberg table takes storage_serialization_policy (COMPATIBLE or OPTIMIZED), path_layout (FLAT or HIERARCHICAL), iceberg_version, max_data_extension_time, and change_tracking. An external table takes the settings that decide which files it reads and when it picks up new ones, a dynamic table takes the warehouse that refreshes it, and both dynamic and hybrid tables take max_data_extension_time:

iceberg_table "FACT_CLAIM" {  schema                       = schema.CLAIMS  external_volume              = "CLAIMS_VOL"  catalog                      = "SNOWFLAKE"  base_location                = "claims/fact_claim"  partition_by                 = ["MONTH(SERVICE_DATE)"]  storage_serialization_policy = OPTIMIZED  iceberg_version              = 2  max_data_extension_time      = 14  column "CLAIM_SK" {    null = false    type = NUMBER(38)  }}
external_table "EXT_CLAIM_FILES" {  schema            = schema.CLAIMS  partition_by      = ["INGEST_DATE"]  pattern           = ".*837.*[.]csv"  auto_refresh      = false  refresh_on_create = false  column "INGEST_DATE" {    null = false    type = DATE    as   = "TO_DATE(SPLIT_PART(METADATA$FILENAME, '/', 3), 'YYYY-MM-DD')"  }  location {    stage = stage.CLAIM_STAGE    path  = "837/"  }}
dynamic_table "DT_CLAIM_MONTHLY" {  schema                  = schema.CLAIMS  target_lag              = "60 minutes"  refresh_mode            = FULL  warehouse               = "CLAIMS_WH"  max_data_extension_time = 9  as                      = "SELECT PLAN_ID FROM CLAIM_STG"}

Snowflake keeps change tracking on for an Iceberg table and rejects the statement that would turn it off, so change_tracking = true is accepted and recorded as nothing, which keeps it from replanning on every diff, and change_tracking = false is rejected with an error rather than planned into a statement that would fail.

Row access, aggregation, and join policies can now be attached to external and Iceberg tables as well, and masking and projection policies to the columns of an Iceberg table. See Snowflake policies for the attachment syntax.

Stages and Functions

An external stage takes a credentials map, and a function takes immutable, which declares the volatility Snowflake defaults to VOLATILE for:

stage "CLAIM_STAGE" {  schema = schema.CLAIMS  url    = "s3://bucket/edi/"  credentials = {    AWS_KEY_ID     = "AKIA"    AWS_SECRET_KEY = "shhh"  }}
function "FN_ALLOWED_AMOUNT" {  schema = schema.PUBLIC  lang   = SQL  arg "BILLED" {    type = FLOAT  }  return    = FLOAT  as        = "BILLED"  immutable = true}
  • Credentials name a cloud location, so Snowflake takes them only together with a url and never together with a storage_integration. Both rules are checked when the file is evaluated.
  • Snowflake never reports credentials back, so they are applied when the stage is created and never written into an inspected document.
  • immutable = false is the default and records nothing, so it compares equal to an inspected function that reports VOLATILE.

Diffing Credentials on an Existing Stage

Because the inspected side never holds credentials, the two can only be compared by taking the declared ones at face value, which is what allowing sensitive values asks for. On an existing stage the change is therefore skipped unless the env opts in with sensitive = ALLOW:

atlas.hcl
env "snow" {  schema {    mode "snowflake" {      sensitive = ALLOW    }  }}

This covers the declarative flow only. migrate diff clears the flag even when the active env sets it, so a credential is never written to a migration file. Rotate one with schema apply, or keep the value out of the schema and set it on the stage directly.

Getting Started

Snowflake support is part of Atlas Pro. Run atlas login to get started, and see the HCL reference for the full set of attributes on each block.

improvementsnowflakewarehousesicebergstages