Library · Data Practice OS
Infrastructure as code for the data platform
Reference guide · Published · Source reviewed
The answer in one line: one declarative tool makes the platform containers (accounts, databases, schemas, roles, grants, integrations), dbt fills them (tables and views), and no object has two owners.
Source and status. This page draws on a platform team's Options paper: Snowflake infrastructure as code - Terraform vs DCM (draft, 30 Oct 2026; the team has not agreed the recommendation) and Snowflake platform: proposed §4 Terraform and dbt split. The scores below are the platform team's, for the platform team's starting point. Re-score for your own estate with Options paper and fact check.
The split of responsibilities
| Layer | Tool | Objects |
|---|---|---|
| Cloud (AWS) | Terraform (cloud infra repo) | KMS keys, IAM role for the storage integration, buckets |
| Data platform containers | Terraform (platform infra repo) | Databases or catalogs, schemas, roles, grants, warehouses, storage integrations, stages, network rules, secrets, service users |
| Data | dbt (pipeline repo) | Tables, views, tests, docs. dbt does not make databases or roles |
| Jobs and apps (Databricks) | Databricks Asset Bundles | Jobs, pipelines, model serving, apps |
The platform team rejected infrastructure in the dbt repos, because the pipeline would need high privileges, and infrastructure and pipeline changes need different reviews. It also rejected imperative migration scripts (for example schemachange): they record history but have no target state and no drift detection, and they add a third tool.
Terraform vs Snowflake DCM: what the platform team found
Snowflake DCM Projects is Snowflake-native. Definitions are SQL and there is no state file. Terraform uses the snowflakedb/snowflake provider.
| Criterion (the platform team weight) | DCM only | Terraform only | Split by level |
|---|---|---|---|
| Object coverage (3) | M: no integrations, secrets, users or PrivateLink | H | H |
| One tool for both sides of the AWS trust (2) | L | H | H |
| Team fit (3) | L | H | M |
| CI and approvals (3) | L: no CI yet | H | M |
| Drift detection (2) | M | H | M |
| Environments and accounts (2) | H | H | M |
| Safety and rollback (3) | L: no rollback; purge drops everything |
M | L |
| Vendor support (2) | H | M: some resources preview | M |
| Migration effort (2) | H | L | M |
| Total (max 66) | 39 | 57 | 46 |
The platform team recommends Terraform only, moved in steps. A later proposal (D-047, not confirmed) starts narrower: Terraform makes the new platform objects first, and other object classes join as their own plan items confirm them.
Rules that generalise
- One owner per object (One owner per object). Two tools managing one object revert each other's changes. Write the boundary in the README of every repo involved.
- Deploy from CI with a service user, never from a laptop with a personal
ACCOUNTADMIN. Plan on every pull request; apply only after approval. - One tool holds both sides of a trust. The storage integration and its IAM role depend on each other's external ID, so put them in one tool and one review.
- Prefer stable, typed resources. In the Snowflake provider,
storage_integration_aws,stage_external_s3,stage_internalandfile_format_*are stable. Generic stage and file format resources, external access and notification integrations, procedures, functions, pipes, tables and dynamic tables are preview, and Snowflake does not officially support preview resources. Pin the provider version and upgrade in its own pull request. Verify the current status in the provider docs. - Do not make tables, views, procedures or tasks in Terraform. Use dbt or a reviewed SQL deploy step in the pipeline repo. Tasks stay
started = falseuntil tested. - Protect against drops. Put
prevent_destroyon databases and schemas, and review every plan that has a destroy. - Migrate by import, not by re-creation. Use
importblocks one group at a time, and compareSHOWoutput with state after each group. Mark the old repos read-only after the last import. - Secrets in state. Encrypt the state bucket and restrict reads to the CI role and DevOps.
On Databricks
Use the Databricks Terraform provider for workspaces, Unity Catalog metastores, catalogs, schemas, grants, external locations and storage credentials. Use Asset Bundles for jobs, pipelines and apps. The same one-owner rule applies: dbt or Lakeflow pipelines own tables, and Terraform does not.
Not when
- On a small, single-environment pilot, a reviewed SQL script in CI can be enough. Move to Terraform before there is a second environment.
- Do not adopt two infrastructure tools to save migration effort. The platform team's analysis treats migration as a one-off cost, while the gaps of a second tool persist.
Related: CI/CD and environments, Naming conventions, ADR-003: dbt as the transformation standard.