dbt Cheat Sheet

A working reference for dbt Core: the commands you run daily, the node selection syntax that saves you from rebuilding the whole project, and the config blocks that decide how a model lands in the warehouse. Everything here is dbt 1.5 or later, and the same commands work in the dbt Cloud IDE.

Everyday commands

Install package dependencies
dbt deps
dbt compile
# output lands in target/compiled/
dbt test
dbt seed --full-refresh
dbt docs generate
dbt docs serve

Selecting what to run

dbt run --select orders
A model and everything downstream
dbt run --select orders+
A model and everything upstream
dbt run --select +orders
One layer up and down only
dbt run --select 1+orders+1
A whole folder
dbt run --select path:models/marts
dbt run --select tag:daily
dbt run --select source:stripe+
Exclude something
dbt run --select marts.* --exclude tag:slow
dbt run --select "state:modified+" --state ./prod-artifacts
Retry only what failed
dbt build --select result:error+ --state ./target
dbt run --select orders --full-refresh

Model configuration

{{ config(materialized='table') }}

select * from {{ ref('stg_orders') }}
Set it for a folder in dbt_project.yml
models:
  my_project:
    marts:
      +materialized: table
      +tags: [daily]
select * from {{ ref('stg_orders') }}
Reference a raw source table
select * from {{ source('stripe', 'charges') }}
Declare that source
version: 2
sources:
  - name: stripe
    schema: raw_stripe
    tables:
      - name: charges
{{ config(materialized='incremental', unique_key='id') }}

select * from {{ ref('stg_orders') }}
{% if is_incremental() %}
where updated_at > (select max(updated_at) from {{ this }})
{% endif %}
A snapshot
{% snapshot orders_snapshot %}
{{ config(unique_key='id', strategy='timestamp', updated_at='updated_at') }}
select * from {{ source('app', 'orders') }}
{% endsnapshot %}
{{ config(post_hook='grant select on {{ this }} to role analyst') }}

Tests and documentation

Built-in tests in a YAML file
version: 2
models:
  - name: orders
    description: One row per customer order.
    columns:
      - name: id
        tests: [unique, not_null]
      - name: customer_id
        tests:
          - relationships:
              to: ref('customers')
              field: id
Accepted values
      - name: status
        tests:
          - accepted_values:
              values: ['new', 'shipped', 'cancelled']
-- tests/assert_totals_positive.sql
select * from {{ ref('orders') }} where total < 0
A reusable generic test
{% test positive(model, column_name) %}
select * from {{ model }} where {{ column_name }} < 0
{% endtest %}
Store the failing rows
dbt test --store-failures
Test one model only
dbt test --select orders

Jinja, variables and connection

vars:
  start_date: '2026-01-01'
Use one, with a default
where day >= '{{ var('start_date', '2026-01-01') }}'
Override at the command line
dbt run --vars '{"start_date": "2026-08-01"}'
{% macro cents_to_euros(column_name) %}
  ({{ column_name }} / 100.0)::numeric(10,2)
{% endmacro %}
packages:
  - package: dbt-labs/dbt_utils
    version: [">=1.1.0", "<2.0.0"]
A useful dbt_utils macro
select {{ dbt_utils.generate_surrogate_key(['order_id', 'line_no']) }} as id
Loop over a list
{% for status in ['new', 'shipped'] %}
  sum(case when status = '{{ status }}' then 1 else 0 end) as {{ status }}_count{{ ',' if not loop.last }}
{% endfor %}
my_project:
  target: dev
  outputs:
    dev:
      type: postgres
      host: localhost
      user: "{{ env_var('DBT_USER') }}"
      password: "{{ env_var('DBT_PASSWORD') }}"
      dbname: analytics
      schema: dbt_kim
      threads: 4
Run against another target
dbt run --target prod

All 25 dbt how-to guides

Each guide is a short answer with examples you can copy and run, plus the gotchas and errors that come with it.

Run dbt queries without a desktop client

SaturnSQL is a browser-based SQL editor for teams: shared query library, schema-aware autocomplete, and scheduled exports to Google Sheets and Slack.

Try it free

The same tasks in other databases