dbt model versions are the official mechanism for rolling out breaking changes safely. By referencing models with an explicit v and migrating consumers through a compatibility layer, you get incident-free releases and instant rollback in the same workflow.
This article hits the exam-relevant points, while also covering the cutover order and compatibility-view patterns that actually trip people up in the field. Everything is based on the stable behavior documented in the official dbt docs.
Analytics models tend to live for a long time, so breaking changes like column drops and semantic shifts are unavoidable. dbt model versions give you a way to run the old and new versions side by side and migrate consumers on a planned schedule.
The strategy is simple. Producers (upstream) build both versions at once. Consumers pin to a specific version using ref. External-facing stable names are served by compatibility views, and cutover is just swapping the view's underlying reference.
| Operations Pattern | Pros | Risks / Caveats |
|---|---|---|
| Direct replace under a fixed name (Create or Replace) | Simple and fast operationally | A breaking change instantly breaks every consumer; rolling back is hard |
| Coexisting versions (versioned models) | Plan migration per consumer | Long coexistence costs money — plan the cleanup |
| Stable name served by compatibility view | Cutover is just swapping the view target — instant and safe | More view management; verify privileges and dependencies |
End-to-end view of coexistence and staged cutover
Example of swapping a compatibility view (the same idea works on Snowflake and Databricks)
-- Switch the stable-name compatibility view from v1 to v2.
-- Existing queries always read the stable name; only the view changes.
CREATE OR REPLACE VIEW analytics.dim_customers AS
SELECT * FROM analytics.versioned.dim_customers_v2;Model versions are declared in YAML properties. You can give each version its own description, tests, and contract. On the reference side, you pin the dependency by passing the version to ref explicitly.
Organizationally, the safe pattern is two-layered: upstream and intermediate models always pin an explicit version with ref, while external-facing names are delegated to compatibility views.
YAML and ref example
# models/sources_and_marts.yml
models:
- name: dim_customers
description: Customer dimension (stable name exposed via compat view)
versions:
- v: 1
description: Legacy schema (email nullable)
tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns: [customer_id]
- v: 2
description: New schema (email NOT NULL, country_code added)
tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns: [customer_id]
- not_null:
column_name: email
-- models/dim_customers_v2.sql (example)
-- Definition for v=2. The SQL file can live anywhere, but naming
-- it with the version suffix keeps operations clean.
select ...
-- Downstream reference (pinned explicitly to v=2)
select * from {{ ref('dim_customers', v=2) }}The key to version operations is writing down the contract you must not break. Setting dbt contracts to enforced fails the build if column order, type, or presence drifts from the model definition.
When you introduce a breaking change, declare a new version that satisfies its own contract, run it side by side, and retire the old version once all consumers have migrated.
Contract declaration example (enforced per version)
# models/marts.yml
models:
- name: dim_customers
versions:
- v: 1
config:
contract:
enforced: true
columns:
- name: customer_id
data_type: integer
tests: [not_null]
- name: email
data_type: varchar
- v: 2
config:
contract:
enforced: true
columns:
- name: customer_id
data_type: integer
tests: [not_null]
- name: email
data_type: varchar
tests: [not_null]
- name: country_code
data_type: varcharExpose external stable names (e.g. analytics.dim_customers) through a compatibility layer. On Snowflake and Databricks, the standard approach is a view, and cutover is a CREATE OR REPLACE VIEW that swaps the reference from v1 to v2.
Bake the cutover into your runbook and put a checklist around it: privileges, metadata, and downstream dependencies (BI tool caches and so on).
Compatibility-view examples by platform
-- Snowflake
CREATE OR REPLACE VIEW analytics.dim_customers AS
SELECT * FROM analytics.versioned.dim_customers_v1; -- before cutover
-- Cutover
CREATE OR REPLACE VIEW analytics.dim_customers AS
SELECT * FROM analytics.versioned.dim_customers_v2; -- after cutover
-- Databricks (Unity Catalog)
CREATE OR REPLACE VIEW analytics.dim_customers AS
SELECT * FROM analytics_versioned.dim_customers_v2;Releases go in this order: prepare → run in parallel → cut over → monitor → retire. Build and validate v2, then cut over the compatibility view for a limited set of consumers first; if everything looks good, expand to the rest. If anything breaks, point the compatibility view back to v1 immediately.
If incremental models or snapshots are involved, plan for a full refresh or a backfill the first time v2 builds.
Typical commands and procedure notes
# 1) Build and test just the v2 model up front
# (Adjust the selector to your environment, e.g. by model name or tag)
dbt run --select dim_customers+ # build with dependencies
dbt test --select dim_customers
# 2) Swap the compatibility view target (rollback is instant)
-- CREATE OR REPLACE VIEW analytics.dim_customers AS SELECT * FROM ..._v2;
# 3) If something is wrong, point it back
-- CREATE OR REPLACE VIEW analytics.dim_customers AS SELECT * FROM ..._v1;The exam loves to test the safe procedure for breaking changes, version specification in ref, and the role of contracts. In the field, people reflexively replace the stable name directly, so designing operations around compatibility views is what separates good teams from accidents.
To avoid migrations that drag on forever, bake the retirement plan into the design from day one: deadline, affected-party notification, and metric monitoring.
Anti-pattern vs. good-pattern examples
# Anti-pattern: change everything in place
# CREATE OR REPLACE TABLE analytics.dim_customers AS ... -- breaking change
# Good pattern: coexistence + compat view
# 1) Build dim_customers_v2
# 2) Swap the analytics.dim_customers compat view to v2
# 3) Monitor; if anything breaks, point the view back to v1Analytics Engineer
問題 1
You're introducing a breaking change (column drop + type change) into a dbt model. Which procedure is safest and easiest to roll back?
正解: A
Coexistence, pinned refs, and a swappable compatibility view give you both staged rollout and instant rollback. Direct replacement or immediate deletion has an unbounded blast radius and is hard to recover from. Auto-following the latest version is just an incident waiting to happen.
What happens if I don't specify a version in ref?
As an organizational policy, we recommend always specifying the version explicitly to avoid unintended schema changes. This pins the dependency and lets you control exactly when each consumer migrates.
Should I include the version in physical relation names (table/view names)?
Yes. Run the physical relations side by side with versioned names (e.g. dim_customers_v1, dim_customers_v2) and expose a stable name through a compatibility view. That makes both cutover and rollback simple.
Are there platform-specific gotchas for Snowflake or Databricks?
The core principle is the same on every warehouse: expose stable names through a view, and switch with a single DDL like CREATE OR REPLACE VIEW. Make sure your runbook covers privilege handoff, refresh of dependent materialized views and caches, and fully-qualified schema names (catalog/schema).
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
dbt Models: SQL-Defined Transformation Units (2026)
Model fundamentals — SELECT-based definitions, naming, refs,...
dbt Analytics Engineering Exam: Complete Guide (2026)
Pass the AE Certification — scope, weighting, sample questio...
dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)
Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...
dbt Project Structure: models/seeds/macros Layout (2026)
Recommended dbt project layout — models, seeds, macros, snap...
dbt_project.yml Explained: Every Config (2026)
Every dbt_project.yml setting that matters — paths, vars, ma...