⚠️ Limitations¶
Objects the Provider Does Not Support Yet¶
The official provider does not cover every Snowflake object, and some resources are only available as preview features.
For everything else there is the snowflake_execute resource: it runs one SQL statement on create and another one on destroy.
resource "snowflake_execute" "grant_create_network_rule" {
provider = snowflake.sysadmin
execute = "GRANT CREATE NETWORK RULE ON SCHEMA COMMON.COMMON TO ROLE SECURITYADMIN"
revert = "REVOKE CREATE NETWORK RULE ON SCHEMA COMMON.COMMON FROM ROLE SECURITYADMIN"
}
The example repository uses it the same way to create a Snowflake-managed MCP server, which has no resource yet.
Keep these cases rare, because snowflake_execute does not detect changes made outside Terraform.
It only runs revert and then execute again when the SQL itself changes.
If an object created this way loses grants when it is replaced, add replace_triggered_by to the grant, so it is granted again too.
For statements over several lines or with results you need to read back, the Snowflake SQL provider is an alternative.
Partial Application of Changes¶
Snowflake runs DDL statements one by one and commits each of them right away. If an apply fails halfway, the account is left somewhere between the old and the new configuration.
SnowDDL handles this by repairing the objects on its next run. SnowForm relies on Terraform’s own mechanism instead: the state records every resource as soon as it is created, also when the apply fails later. Fix the error and run plan and apply again. Terraform only creates what is still missing, and replaces resources it marked as tainted because they failed halfway. You can repeat this as often as needed.
Two things make this work reliably:
A remote state backend. If the state from the failed run is lost, the next run does not know about the objects that were already created, and fails with
already exists.Explicit
depends_onbetween resources that Terraform cannot link by reference, like a grant on a schema that is created elsewhere. Without it, Terraform can run them in parallel, and the grant fails because the schema does not exist yet.
Renaming Objects¶
SnowDDL uses full object names as identifiers. A rename in its config therefore drops the old object and creates a new one, unless you rename it by hand first (see SnowDDL renaming).
In SnowForm, changing the name of a database, schema, warehouse or role renames it in place with ALTER ... RENAME TO.
Data and ownership stay, and grants that reference the object are revoked and granted again under the new name.
Renaming the Terraform resource itself is a different thing.
If you change the resource address, for example snowflake_database.sales to snowflake_database.revenue, Terraform would drop the database and create a new one.
Add a moved block, so it keeps the existing object:
moved {
from = snowflake_database.sales
to = snowflake_database.revenue
}
The same applies to modules and to for_each keys, for example when a schema is renamed in the schemas list of the access roles module.
Lowercase Identifiers¶
Lowercase and mixed case identifiers work and behave like they do in Snowflake: they have to be quoted everywhere. We recommend uppercase identifiers, which is also what the modules expect.