Contracts, model versioning, deprecation, and access controls โ the guardrails that make dbt projects production-safe.
Domain 2 covers the governance layer of dbt โ features that enforce structure, manage change, and control who can use what. These were introduced in dbt 1.5+ and appear consistently on the exam.
Enforce model shape โ column names, data types, and constraints
Safely evolve models without breaking downstream consumers
Public, private, and protected access levels for cross-project use
Governance features are newer (dbt 1.5+) and less commonly practiced โ which means candidates who study them carefully have an edge. The exam tests your ability to:
Only public models can be referenced across dbt projects. Private models can only be used within the same group. Protected models (the default) can be used anywhere in the same project. This distinction is a frequent exam topic.
Click each topic to expand study notes.
contract: {enforced: true} with explicit column definitionsversions: block listing version numbers and optional defined-in paths{{ ref('model_name', version=2) }}latest_version in the .yml specifies which version ref('model_name') (without version) resolves todeprecation_date marks a version as deprecated โ dbt emits a warning when it's referencedAccessible from any dbt project. Use for stable, shared interfaces (e.g. mart models consumed by other teams).
Default access. Accessible anywhere within the same project. Safe for most models.
Only accessible within the same group. Use for internal implementation details you don't want other teams to depend on.
access: public | protected | private in the model's .ymlpublicCheck off each item as you study. Domain 2 is focused โ master all of these.
Column names, data types, and optional constraints (NOT NULL, PRIMARY KEY)
Table and incremental only โ not view or ephemeral
Add contract: {enforced: true} and explicit column definitions in .yml
Know what each allows and when to use each
Critical distinction โ this appears on the exam
Private models are scoped to their group โ other groups in the same project cannot ref() them
Set latest_version, add a deprecation_date to v1, and ref() v2 from a downstream model
{{ ref('model_name', version=2) }} โ version is a keyword argument
dbt emits a warning when a deprecated version is referenced โ it doesn't fail immediately
docs.getdbt.com/docs/collaborate/govern โ review all three sections
Key YAML syntax for Domain 2 โ these patterns appear in exam questions.
5 exam-style questions on governance.
Domain 2 is focused โ 3โ4 days of targeted study is sufficient.
Contracts only work with table/incremental
Setting contract: enforced: true on a view or ephemeral model causes a dbt compilation error. Contracts require the model to be materialized as a table or incremental.
Before adding a contract, confirm the model is materialized as table or incremental. If it's a view, change the materialization or remove the contract.
Cross-project requires public, not just protected
Attempting to ref() a protected model from another dbt project fails at compile time. Protected = same project only.
Explicitly set access: public on any model you want other dbt projects to be able to reference.
Deprecated models still run โ they just warn
Candidates think deprecation_date automatically removes or stops the model from running after the date. It only emits a warning โ it doesn't fail or stop anything.
Deprecation is a communication mechanism โ it warns consumers to migrate. You must manually delete the deprecated version after the migration window closes.
Partial column specs cause runtime failures
A contract with enforced: true but incomplete column definitions (missing data_type) will fail. dbt requires all contracted columns to have an explicit data type.
Every column listed under a contract must include a data_type. Review your platform's supported data types in the dbt docs to ensure correct values.
Unexpected version resolution
ref('dim_customers') without a version= argument resolves to the latest_version, not necessarily v1. If latest_version is set to v2, your model may silently use the new schema.
During migration windows, explicitly pin consumers to a version: ref('dim_customers', version=1) until you're ready to upgrade to v2.
access: config behave as protected โ accessible anywhere within the same dbt project, but not from other projects.latest_version determines which version ref('model_name') (without an explicit version argument) resolves to. Setting it to v2 means all unversioned references automatically point to v2. Downstream models that haven't explicitly pinned to v1 will use v2.