Организация YAML-файлов
В dbt-проекте YAML — это не код, а метаданные: descriptions, tests, configs. Это «второй слой» проекта, параллельный SQL-файлам.
Можно сложить всё в один гигантский schema.yml на 1500 строк (так делалось в старых dbt-проектах). Можно класть YAML индивидуально к каждой .sql модели (stg_jaffle__customers.yml рядом с stg_jaffle__customers.sql). Современная convention — что-то посередине: один YAML на директорию, со специальным именем.
В этом уроке — какие YAML бывают, как их называть, что в них кладётся.
Какие YAML существуют в dbt
| Тип YAML | Назначение |
|---|---|
| Sources YAML | Декларация source-таблиц. Какие схемы / таблицы есть в warehouse. |
| Models YAML | Descriptions + tests + configs для моделей. Один на директорию. |
| Seeds YAML | Descriptions + tests + column_types для seeds. |
| Snapshots YAML | Декларация snapshots (1.9+) + descriptions. |
| Macros YAML | Descriptions для macros, аргументы. |
| Exposures YAML | Декларация exposures (dashboards / ML / apps). |
| Doc blocks | .md файлы с многострочными descriptions через {% docs %}. |
Все они опциональны, но без них:
- Source без YAML не доступен через
source(). - Модель без YAML — без descriptions и без тестов.
- Snapshot 1.9+ без YAML — это просто SQL, dbt не знает что это snapshot.
Convention: один YAML на директорию
Современный паттерн — один YAML на директорию models:
models/staging/jaffle/
_jaffle__sources.yml ← sources в этом домене
_jaffle__models.yml ← descriptions + tests для всех stg_jaffle__*
stg_jaffle__customers.sql
stg_jaffle__orders.sql
stg_jaffle__order_items.sql
stg_jaffle__payments.sql
Преимущества:
- Один файл — один контекст. Все source jaffle в одном
_jaffle__sources.yml. Все staging-модели jaffle в одном_jaffle__models.yml. Контекст не размазан по 5 файлам. - Локальность правок. Изменили stg-модель — открыли
_jaffle__models.yml, поправили description. Не нужно искать YAML по проекту. - Code review понятен. PR с правкой одного source изменит 2 файла (sources.yml + models.yml), не 10.
Альтернатива — один YAML на модель (stg_jaffle__customers.yml рядом с SQL) — допустима, но в больших проектах создаёт хаос: вместо 10 файлов в директории становится 20.
Naming convention для YAML
Идиоматический формат: _<group>__<type>.yml.
_<group>__sources.yml— sources деклараций._<group>__models.yml— modelов descriptions + tests._<group>__seeds.yml— seed descriptions.
Почему подчёркивание в начале (_jaffle__models.yml, а не jaffle__models.yml)?
Сортировка файлов в листинге: подчёркивание начинается раньше букв в ASCII-порядке. В IDE / в ls подчёркнутые файлы идут сверху. Открываешь директорию — сразу видишь YAML (метаданные), потом уже SQL-файлы.
Почему <group>__<type> (двойное подчёркивание)?
Та же логика, что в именах моделей stg_<source>__<table>. Двойное подчёркивание отделяет группу от типа. Парсимо.
Примеры хороших имён:
_jaffle__sources.yml_jaffle__models.yml_core__models.yml(для marts/core/)_finance__models.yml(для marts/finance/)_reference__seeds.yml(для seeds/reference/)
Антипаттерны:
schema.yml— устаревшее наследие 2018 года. Имя ничего не говорит.sources.yml— где? У какой группы? В большом проекте десятки таких.customers.yml— на одну модель, размазано по 50 файлам.
Структура sources YAML
_<group>__sources.yml — декларация source-системы:
version: 2
sources:
- name: jaffle # имя source, на которое ссылаются модели через source()
description: "Основная app-БД Jaffle Shop"
database: jaffle_shop_db # имя БД в warehouse (опционально, обычно = target.database)
schema: raw_jaffle # имя схемы в warehouse
freshness: # как часто данные должны обновляться
warn_after: { count: 12, period: hour }
error_after: { count: 24, period: hour }
loaded_at_field: _loaded_at # колонка с timestamp загрузки
tables:
- name: customers
description: "Зарегистрированные клиенты Jaffle Shop"
columns:
- name: id
description: "Primary key"
data_tests:
- not_null
- unique
- name: email
description: "Электронная почта"
data_tests:
- not_null
- name: orders
description: "Заказы клиентов"
loaded_at_field: created_at # переопределение для конкретной таблицы
freshness:
warn_after: { count: 1, period: hour }
columns:
- name: id
data_tests:
- not_null
- unique
Что важно:
name: jaffle— это логическое имя, которое появляется вsource('jaffle', 'customers'). Не обязательно совпадает со схемой в БД.schema: raw_jaffle— физическая схема. Может отличаться от dbt-логического имени.freshness— мониторинг. Если данные вcustomersстарше 24 часов —dbt source freshnessупадёт.loaded_at_field— какая колонка показывает «когда строка попала в warehouse» (а не время в исходной системе).- Тесты на source — нужны. Если source-данные грязные — все downstream сломаются.
Один файл может содержать несколько sources:
version: 2
sources:
- name: jaffle
schema: raw_jaffle
tables:
- name: customers
- name: orders
- name: shopify
schema: raw_shopify
tables:
- name: products
- name: inventory
Но рекомендованный паттерн — один source на YAML, чтобы файл соответствовал директории.
Структура models YAML
_<group>__models.yml:
version: 2
models:
- name: stg_jaffle__customers
description: |
Чищенные данные клиентов из jaffle source.
1:1 с raw_jaffle.customers, но с переименованными колонками и фильтром is_deleted.
config:
materialized: view
tags: ['staging', 'jaffle']
columns:
- name: customer_id
description: "Primary key — ID клиента"
data_tests:
- not_null
- unique
- name: email
description: "Email клиента, нормализован (lowercase, trimmed)"
data_tests:
- not_null
- name: created_date
description: "Дата создания клиента"
- name: stg_jaffle__orders
description: "Чищенные заказы из jaffle source"
columns:
- name: order_id
data_tests:
- not_null
- unique
- name: customer_id
data_tests:
- not_null
- relationships:
to: ref('stg_jaffle__customers')
field: customer_id
Несколько deep-фич:
- description: | — pipe позволяет многострочное описание. Markdown поддерживается.
- config: — конфигурация модели прямо в YAML. Альтернатива
{{ config(...) }}в SQL. В 1.9+ это рекомендованный путь. - tags — для node selection (
dbt run --select tag:staging). - columns — описание + тесты на каждую колонку.
- relationships — тест FK на ref другой модели.
В 1.10 многие конфиги (tags, meta, group, access) переехали из top-level в config: блок. Старый синтаксис ещё работает, но с warning.
Структура snapshots YAML (1.9+)
# snapshots/_snapshots.yml
snapshots:
- name: customers_snapshot
description: "SCD2-история customers для атрибуции продаж по tier"
relation: source('jaffle', 'customers')
config:
schema: snapshots
unique_key: customer_id
strategy: timestamp
updated_at: updated_at
- name: products_snapshot
description: "SCD2-история products: цена и категория"
relation: source('jaffle', 'products')
config:
schema: snapshots
unique_key: product_id
strategy: check
check_cols:
- price
- category
Snapshots обычно держат в одном YAML на проект, так как их мало (5-20 на типичный проект).
Структура seeds YAML
# seeds/reference/_reference__seeds.yml
version: 2
seeds:
- name: country_codes
description: "ISO-3166 коды стран с маппингом на регионы и валюты"
config:
column_types:
country_code: varchar(2)
country_name: varchar(100)
region: varchar(20)
columns:
- name: country_code
description: "ISO alpha-2 code"
data_tests:
- unique
- not_null
- name: region
data_tests:
- accepted_values:
values: ['Americas', 'EMEA', 'APAC']
- name: product_categories
description: "Категории продуктов из бизнеса"
columns:
- name: category_id
data_tests:
- unique
- not_null
То же самое что и models — descriptions + tests + config (включая column_types).
Doc blocks: .md файлы
Если description длинный (несколько абзацев, code samples, ссылки), писать его прямо в YAML неудобно. Альтернатива — doc blocks в .md файлах.
models/staging/jaffle/_jaffle__docs.md:
{% docs jaffle_overview %}
Jaffle Shop — это демо-приложение dbt Labs. Включает customers, orders,
order_items, payments. Размер: ~10к строк customers, ~50к orders.
Источник: `raw_jaffle` схема, заливается Fivetran каждый час.
История загрузки: с июня 2025.
{% enddocs %}
{% docs customer_id %}
Уникальный идентификатор клиента. Sequential integer, начинается с 1.
Никогда не reused (даже если клиент удалён).
В downstream-моделях используется как primary key dim_customers.
{% enddocs %}
И в YAML ссылаемся через {{ doc('name') }}:
sources:
- name: jaffle
description: '{{ doc("jaffle_overview") }}'
tables:
- name: customers
columns:
- name: id
description: '{{ doc("customer_id") }}'
Преимущества:
- Reuse.
customer_iddescription пишется один раз, используется в 10 моделях. - Markdown-форматирование (code blocks, ссылки, списки) работает.
- Лучше для длинных описаний — отдельный .md файл удобнее редактировать, чем многострочный YAML.
Doc blocks отображаются в dbt docs serve UI с полным markdown-рендерингом.
Пример полной структуры YAML в Jaffle Shop
models/
staging/
jaffle/
_jaffle__sources.yml ← декларация source jaffle
_jaffle__models.yml ← descriptions + tests для всех stg_jaffle__*
_jaffle__docs.md ← doc blocks (опционально)
stg_jaffle__customers.sql
stg_jaffle__orders.sql
intermediate/
finance/
_int_finance__models.yml ← descriptions + tests для int_*
int_payments_joined.sql
marts/
core/
_core__models.yml ← descriptions + tests для fct_/dim_*
_core__docs.md ← doc blocks для core домена
fct_orders.sql
dim_customers.sql
finance/
_finance__models.yml
revenue_daily.sql
snapshots/
_snapshots.yml ← все snapshots декларации
customers_snapshot.yml
seeds/
reference/
_reference__seeds.yml ← descriptions + tests для seeds
country_codes.csv
Принцип: одна директория = одна группа YAML-файлов. Хочется добавить новую модель в jaffle — открываешь _jaffle__models.yml, добавляешь запись. Не нужно искать.
Что НЕ делать
-
Один schema.yml на 5000 строк. Старая практика 2018-2019. Сейчас антипаттерн. Невозможно навигировать, git diff показывает изменения сразу в 50 моделях.
-
YAML рядом с каждой моделью.
stg_jaffle__customers.ymlрядом сstg_jaffle__customers.sql. Допустимо, но в большом проекте — хаос: 200 YAML вместо 20. -
YAML без descriptions. Только
name:иtests:— но безdescription. Через год невозможно понять, что эта модель. -
Дублирование описания. То же самое описание в YAML и в SQL комментарии. Источник правды должен быть один — обычно YAML.
-
YAML с разными версиями.
version: 1иversion: 2в разных файлах. С 2020 года стандарт —version: 2. Всегда так. -
Длинные description прямо в YAML. Если description больше 5 строк — выноси в doc block (.md файл).
Попробуй сам
В вашем dbt-проекте создайте структуру:
models/staging/jaffle/
_jaffle__sources.yml
_jaffle__models.yml
stg_jaffle__customers.sql
stg_jaffle__orders.sql
В _jaffle__sources.yml:
version: 2
sources:
- name: jaffle
schema: main
description: "Demo Jaffle Shop data"
tables:
- name: raw_customers
- name: raw_orders
В _jaffle__models.yml:
version: 2
models:
- name: stg_jaffle__customers
description: "Чищенные customers"
columns:
- name: customer_id
data_tests: [not_null, unique]
- name: stg_jaffle__orders
description: "Чищенные orders"
columns:
- name: order_id
data_tests: [not_null, unique]
- name: customer_id
data_tests:
- relationships:
to: ref('stg_jaffle__customers')
field: customer_id
Запустите dbt build. Что произойдёт:
- dbt парсит YAML, обнаруживает source и две модели.
- Запускает модели по DAG.
- Запускает тесты: not_null, unique, relationships.
Бонус: создайте doc block в _jaffle__docs.md:
{% docs jaffle_intro %}
**Jaffle Shop** — учебный проект dbt. См. [официальный repo](https://github.com/dbt-labs/jaffle_shop).
{% enddocs %}
И в _jaffle__sources.yml подключите: description: '{{ doc("jaffle_intro") }}'. Запустите dbt docs generate && dbt docs serve. Откройте UI, найдите source jaffle — увидите rendered markdown.
Ключевые выводы
- YAML — это метаданные, параллельный слой к SQL. Не код, а описания + тесты + конфиги.
- Convention: один YAML на директорию с именем
_<group>__<type>.yml. Подчёркивание в начале — чтобы YAML был сверху в листинге. - Типы YAML: sources, models, seeds, snapshots, macros, exposures. Каждый со своей секцией top-level (
sources:,models:,seeds:). - В
sources YAML: декларация source + freshness + loaded_at_field + tests на колонках. - В
models YAML: descriptions + tests + config + columns.relationshipsтест проверяет FK. - Doc blocks (
.md) для длинных descriptions.{% docs name %}...{% enddocs %}, ссылаются через{{ doc('name') }}в YAML. - Антипаттерн —
schema.ymlна весь проект (старое наследие) или YAML рядом с каждой моделью (хаос).