DataLane
← All cheat sheets

Terraform for Data Infrastructure cheat sheet

Managing warehouses, buckets, and Snowflake objects as code — state, modules, and the workflow that avoids drift.

Cloud PlatformsAdvanced5 sections

Workflow

terraform init -backend-config=env/prod.hcl
Per-environment backend config keeps one codebase managing multiple state files without copy-pasted directories.
terraform plan -out=tfplan
Always save the plan and apply that artifact. Applying without a saved plan can execute a different change than reviewed.
terraform apply tfplan
Applies exactly what was reviewed. This is the difference between infrastructure as code and infrastructure as vibes.
terraform fmt -recursive && terraform validate
Cheap pre-commit checks that eliminate most review noise.
terraform plan -detailed-exitcode
Exit code 2 means changes pending. Use it in CI to detect drift on a schedule.

State

terraform { backend "s3" { bucket = "tf-state" key = "data-platform/prod.tfstate" use_lockfile = true encrypt = true } }
Remote state with locking. Local state on a laptop is how two engineers destroy each other's warehouses.
terraform state list
Inventory of what Terraform believes it owns. First command when plan wants to recreate something that exists.
terraform import snowflake_database.analytics ANALYTICS
Adopt existing objects instead of recreating them. Essential when codifying a platform built by hand.
terraform state rm module.old_warehouse
Stop managing a resource without destroying it. The safe path when splitting one state file into several.
moved blocks over state mv
Declarative refactoring in code, reviewable in the PR, instead of imperative state surgery nobody can audit.

Structure

modules/ snowflake-database/ s3-lake-bucket/ envs/ prod/ dev/
Modules for repeated patterns, thin env roots that pass variables. Avoid one giant root module.
for_each over a map, not count
count reindexes on removal and destroys unrelated resources. for_each keys are stable — always prefer it.
locals { layers = { bronze = 30, silver = 90, gold = 365 } }
Drive resource creation from data so adding a layer is a one-line change.
terraform_remote_state or data sources over hardcoded ARNs
Reference real outputs across stacks rather than pasting identifiers that silently go stale.

Snowflake provider

resource "snowflake_warehouse" "etl" { name = "ETL_WH" warehouse_size = "SMALL" auto_suspend = 60 auto_resume = true }
Warehouses as code makes auto_suspend a reviewed decision rather than an inherited default that burns credits.
resource "snowflake_grant_privileges_to_account_role" "read" { account_role_name = snowflake_account_role.analyst.name privileges = ["SELECT"] on_schema_object { future { object_type_plural = "TABLES", in_schema = "..." } } }
Future grants so new tables inherit access. Without them every new model needs a manual grant.
Manage roles and warehouses in Terraform; leave tables to dbt
The clean split. Terraform owns the container and permissions; dbt owns the objects inside it.
Provider version pinning: ~> 2.0
The Snowflake provider has made breaking changes across majors. Unpinned versions break CI without a code change.

Pitfalls

Secrets in .tfvars committed to Git
Use environment variables or a secret store. State files also contain secrets — encrypt the backend and restrict it.
Manual console changes
Drift makes the next plan destructive. Either import the change or revert it; never leave it unreconciled.
One state file for the whole company
A single blast radius and serialized applies. Split by lifecycle — network, warehouse, and per-team resources.
prevent_destroy on stateful resources
Lifecycle guard on buckets and databases. Turns an accidental destroy into a plan-time error.

From DataLane — tutorials at/blog, practice SQL live in theplayground.

↑↓ navigate openesc close