Home Database CI/CD: Terraform, dbt, and Schema Evolution
Advanced 3 min · July 17, 2026

CI/CD: Terraform, dbt, and Schema Evolution

Master Snowflake CI/CD with Terraform for infrastructure, dbt for transformations, and schema evolution strategies.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
Production
production tested
July 17, 2026
last updated
2,439
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic knowledge of SQL and Snowflake
  • Familiarity with Git and CI/CD concepts
  • Terraform installed (v1.0+)
  • dbt installed (v1.0+)
  • Snowflake account with ACCOUNTADMIN access
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Use Terraform to manage Snowflake warehouses, databases, and roles as code.
  • Use dbt for version-controlled SQL transformations and testing.
  • Handle schema changes with backward-compatible migrations and zero-downtime deploys.
  • Automate CI/CD pipelines with GitHub Actions or similar tools.
  • Monitor and rollback using dbt artifacts and Snowflake time travel.
✦ Definition~90s read
What is CI/CD?

Snowflake CI/CD with Terraform and dbt is the practice of automating the deployment and testing of Snowflake infrastructure and data transformations using infrastructure-as-code and SQL transformation tools.

Think of Snowflake CI/CD like a construction crew building a skyscraper.
Plain-English First

Think of Snowflake CI/CD like a construction crew building a skyscraper. Terraform is the blueprint for the building's structure (warehouses, databases). dbt is the team that installs the interior (tables, views, transformations). Schema evolution is like renovating a floor while the building is still occupied—you need to avoid breaking things and ensure everyone can still work. CI/CD automates the process so changes are tested and deployed safely.

In modern data engineering, Snowflake has become a leading cloud data warehouse, but managing its infrastructure and data transformations manually is error-prone and unscalable. Enter CI/CD—Continuous Integration and Continuous Deployment—which brings software engineering best practices to data pipelines. This tutorial focuses on three key tools: Terraform for infrastructure-as-code, dbt (data build tool) for SQL transformations, and strategies for schema evolution. You'll learn how to define Snowflake resources (warehouses, databases, roles) in Terraform, version-control your dbt models, and handle schema changes without breaking production. We'll walk through a real-world production incident where a schema change caused a downstream outage, and how to debug it. By the end, you'll have a production-ready CI/CD pipeline that ensures your Snowflake environment is reproducible, testable, and resilient.

1. Setting Up Terraform for Snowflake

Terraform allows you to define Snowflake resources as code. Start by installing the Snowflake provider. Create a main.tf file with provider configuration. Use variables for sensitive info like account and private key. Define a virtual warehouse, database, and schema. Example: resource 'snowflake_warehouse' 'my_wh' { name = 'my_warehouse' warehouse_size = 'X-SMALL' auto_suspend = 60 }. Then run terraform init, plan, apply. Best practice: use remote state (e.g., S3) and separate environments (dev, prod) with workspaces.

main.tfHCL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
provider "snowflake" {
  alias = "admin"
}

resource "snowflake_warehouse" "my_wh" {
  provider       = snowflake.admin
  name           = "MY_WH"
  warehouse_size = "X-SMALL"
  auto_suspend   = 60
}

resource "snowflake_database" "my_db" {
  provider = snowflake.admin
  name     = "MY_DB"
}

resource "snowflake_schema" "my_schema" {
  provider   = snowflake.admin
  database   = snowflake_database.my_db.name
  name       = "MY_SCHEMA"
}
Output
Apply complete! Resources: 3 added.
💡Use Terraform Workspaces
📊 Production Insight
Always use a dedicated service account for Terraform with ACCOUNTADMIN role to avoid permission issues.
🎯 Key Takeaway
Terraform codifies Snowflake infrastructure, making it reproducible and auditable.

2. Managing dbt Models and Tests

dbt transforms data in your warehouse using SQL SELECT statements. Initialize a dbt project with 'dbt init'. Configure profiles.yml with Snowflake connection details. Create models in the models/ folder. Use Jinja templating for dynamic SQL. Example: a model that aggregates sales by month. Add tests using schema.yml: define unique, not_null, and custom tests. Run 'dbt run' to build models and 'dbt test' to validate. Use 'dbt docs generate' for documentation.

models/monthly_sales.sqlSQL
1
2
3
4
5
SELECT
    DATE_TRUNC('month', order_date) AS month,
    SUM(amount) AS total_sales
FROM {{ ref('orders') }}
GROUP BY 1
Output
Model monthly_sales created successfully.
🔥dbt Sources and Ref
📊 Production Insight
Use dbt's 'on_schema_change' setting to handle column additions gracefully: 'append_new_columns' or 'sync_all_columns'.
🎯 Key Takeaway
dbt brings software engineering practices like version control and testing to SQL transformations.

3. Schema Evolution Strategies

Schema evolution is inevitable. Use backward-compatible changes: add columns as NULLable, avoid renaming/dropping without deprecation. In dbt, use 'on_schema_change' to automatically add new columns. For breaking changes, create new models and deprecate old ones. Use Snowflake's Time Travel to rollback if needed. Example: adding a column to a source table. Update dbt model to include the new column. Test with 'dbt test' before deploying.

schema.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
version: 2

models:
  - name: monthly_sales
    columns:
      - name: month
        tests:
          - unique
          - not_null
      - name: total_sales
        tests:
          - not_null

sources:
  - name: raw
    schema: public
    tables:
      - name: orders
        loaded_at_field: loaded_at
        freshness:
          warn_after: {count: 1, period: day}
⚠ Avoid SELECT *
📊 Production Insight
Use dbt's 'exposure' to document downstream consumers of your models, so you know who is affected by schema changes.
🎯 Key Takeaway
Schema evolution requires careful planning: add before remove, deprecate before delete.

4. Building a CI/CD Pipeline with GitHub Actions

Automate testing and deployment. Create a .github/workflows/ci.yml file. Trigger on pull requests to main. Steps: checkout code, set up Terraform, run 'terraform plan' for dev. Set up dbt, run 'dbt deps', 'dbt run', 'dbt test'. If all pass, merge. Then a deploy workflow runs 'terraform apply' and 'dbt run' on prod. Use secrets for Snowflake credentials. Example workflow snippet.

.github/workflows/ci.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: CI
on: [pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: 1.5.0
      - name: Terraform Plan
        run: terraform plan
        env:
          SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
          SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
          SNOWFLAKE_PRIVATE_KEY: ${{ secrets.SNOWFLAKE_PRIVATE_KEY }}
      - name: Setup dbt
        uses: dbt-labs/actions/setup-dbt@v1
      - name: dbt Run and Test
        run: |
          dbt deps
          dbt run
          dbt test
💡Use dbt Artifacts
📊 Production Insight
Separate Terraform and dbt steps: run Terraform plan on PR, but apply only after merge to main.
🎯 Key Takeaway
CI/CD pipelines automate testing and deployment, reducing human error and speeding up releases.

5. Zero-Downtime Deployments with Blue-Green Strategy

For critical pipelines, use blue-green deployment. Maintain two environments (blue and green). Deploy changes to the inactive environment, test, then switch traffic. In Snowflake, this can be achieved by using separate schemas or databases. Use dbt's 'target' configuration to point to different schemas. Example: blue schema 'prod_v1', green schema 'prod_v2'. After validation, update the view or alias to point to the new schema. Use Terraform to manage the switch.

dbt_profiles.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
snowflake:
  target: blue
  outputs:
    blue:
      type: snowflake
      schema: prod_v1
      ...
    green:
      type: snowflake
      schema: prod_v2
      ...
🔥Switch with Views
📊 Production Insight
Monitor query performance after switch; use Snowflake's query history to detect regressions.
🎯 Key Takeaway
Blue-green deployments minimize risk by allowing full validation before switching traffic.

6. Monitoring and Rollback Strategies

Even with CI/CD, issues can slip through. Use dbt's 'source freshness' to detect stale data. Set up alerts on dbt test failures. For rollbacks, Snowflake Time Travel allows you to restore tables to a previous state (up to 90 days). Use 'UNDROP' for dropped objects. In dbt, use 'dbt run --full-refresh' to rebuild models from scratch. For Terraform, use 'terraform state rm' to remove resources and re-import. Example: rolling back a dbt model.

rollback.sqlSQL
1
2
3
4
5
-- Restore dropped table using Time Travel
ALTER TABLE my_table UNDROP;

-- Or query historical data
SELECT * FROM my_table AT (TIMESTAMP => '2025-01-01 12:00:00'::TIMESTAMP);
Output
Table restored successfully.
⚠ Time Travel Costs
📊 Production Insight
Use dbt's 'run_results' table to track historical runs and quickly identify which model introduced a bug.
🎯 Key Takeaway
Monitoring and rollback plans are essential for production resilience.
● Production incidentPOST-MORTEMseverity: high

The Silent Column Drop That Broke Dashboards

Symptom
Business dashboards started showing NULL values for a key metric; some queries failed with 'column not found' errors.
Assumption
The developer assumed dropping a deprecated column was safe because no active queries referenced it.
Root cause
A downstream dbt model still referenced the dropped column via a SELECT * statement, causing the model to fail when the column disappeared.
Fix
Rolled back the column drop using Snowflake Time Travel (UNDROP), then updated the dbt model to explicitly list columns before dropping.
Key lesson
  • Never use SELECT * in production dbt models; always list columns explicitly.
  • Always check downstream dependencies before altering schemas.
  • Use dbt's 'ref' and 'source' freshness to detect breaking changes.
  • Implement a CI step that runs dbt test before deploying schema changes.
  • Have a rollback plan (e.g., Time Travel, versioned deployments).
Production debug guideSymptom to Action4 entries
Symptom · 01
dbt run fails with 'Object already exists'
Fix
Check if the table/view already exists. Use dbt's 'on_schema_change' setting or drop/recreate with '--full-refresh'.
Symptom · 02
Terraform apply fails with 'Insufficient privileges'
Fix
Verify the Terraform service account has ACCOUNTADMIN or necessary grants. Use 'SHOW GRANTS TO USER'.
Symptom · 03
Schema change causes downstream query failures
Fix
Use dbt 'source freshness' and 'exposure' to detect broken dependencies. Rollback using Time Travel.
Symptom · 04
CI pipeline takes too long
Fix
Optimize dbt by using incremental models, limiting test scope, and parallelizing Terraform operations.
★ Quick Debug Cheat SheetCommon symptoms and immediate actions for Snowflake CI/CD issues.
dbt model fails with 'column not found'
Immediate action
Check recent schema changes. Use 'UNDROP' if column was dropped.
Commands
ALTER TABLE my_table UNDROP COLUMN my_column;
dbt run --select my_model
Fix now
Restore column and update model.
Terraform state drift+
Immediate action
Run 'terraform refresh' to sync state.
Commands
terraform refresh
terraform plan
Fix now
Apply the plan to reconcile.
dbt test fails with 'referential integrity'+
Immediate action
Check source data quality. Temporarily disable test if false positive.
Commands
dbt test --select test_name
dbt test --store_failures
Fix now
Fix source data or update test.
ToolPurposeState ManagementTesting
TerraformInfrastructure as CodeState file (remote)Plan/apply validation
dbtData TransformationManifest artifactsdbt test
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
main.tfprovider "snowflake" {1. Setting Up Terraform for Snowflake
modelsmonthly_sales.sqlSELECT2. Managing dbt Models and Tests
schema.ymlversion: 23. Schema Evolution Strategies
.githubworkflowsci.ymlname: CI4. Building a CI/CD Pipeline with GitHub Actions
dbt_profiles.ymlsnowflake:5. Zero-Downtime Deployments with Blue-Green Strategy
rollback.sqlALTER TABLE my_table UNDROP;6. Monitoring and Rollback Strategies

Key takeaways

1
Terraform and dbt together provide a robust CI/CD framework for Snowflake, ensuring infrastructure and transformations are version-controlled and testable.
2
Schema evolution must be handled with backward-compatible changes and thorough testing to avoid production incidents.
3
Always have a rollback plan using Snowflake Time Travel and dbt's rebuild capabilities.

Common mistakes to avoid

3 patterns
×

Using SELECT * in dbt models

×

Running Terraform apply directly on production without plan

×

Not testing schema changes in CI

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How would you implement a CI/CD pipeline for Snowflake using Terraform a...
Q02SENIOR
What strategies do you use for schema evolution in Snowflake?
Q03SENIOR
How do you debug a dbt model that fails after a schema change?
Q01 of 03SENIOR

How would you implement a CI/CD pipeline for Snowflake using Terraform and dbt?

ANSWER
I would set up Terraform to manage Snowflake resources (warehouses, databases, schemas) with separate workspaces for dev and prod. dbt would manage SQL transformations with version control. A GitHub Actions workflow would run Terraform plan and dbt test on pull requests, then apply and run dbt on merge to main.
FAQ · 3 QUESTIONS

Frequently Asked Questions

01
What is the difference between Terraform and dbt in Snowflake CI/CD?
02
How do I handle schema changes without breaking downstream consumers?
03
Can I use Snowflake's Time Travel to rollback a dbt run?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
Verified
production tested
July 17, 2026
last updated
2,439
articles · all by Naren
🔥

That's Snowflake. Mark it forged?

3 min read · try the examples if you haven't

Previous
Migrating to Snowflake: From Redshift, BigQuery, and Legacy Warehouses
24 / 33 · Snowflake
Next
Snowpark Container Services: Deploying Jobs, Services, and Apps