dbt Fundamentals
Back to Contracts, Exposures & Unit Tests

Model Contracts: Enforcing Shape at Build Time

Contracts, constraints, and failing builds on purpose.

6 minutesInteractive tutorial
🎯 Free Guest Mode: You are learning for free. Sign in to save your completion progress and quiz answers.

Generic tests (unique, not_null) check data after it lands. Contracts reject bad builds before they land.

models:
  - name: mart_daily_revenue
    config:
      contract:
        enforced: true
    columns:
      - name: day
        data_type: date
        constraints: [not_null]
      - name: revenue_cents
        data_type: numeric
        constraints: [not_null]

Rules

  1. Contract the marts, not every staging model. Enforce at the boundary consumers read (marts); keep staging flexible for messy sources.
  2. Constraints are the executable half of the contract: not_null, primary_key, foreign_key, check. dbt renders them as real DDL on supported warehouses.
  3. A contract break fails dbt build. That is the point — a renamed column or widened type stops the pipeline instead of silently shifting a dashboard.
  4. Warehouse support varies (BigQuery/Snowflake/Databricks enforce; Postgres adapter renders constraints). Know your engine before promising enforcement.
Question 1 of 4Answer saved0 answered

Where should you enforce dbt model contracts, and why?