Learning Platform
Глоссарий Troubleshooting
Урок 15.03 · 20 мин
Начальный
YAMLOrganization_models.yml_sources.yml_macros.yml

Организация 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 YAMLDescriptions + tests + configs для моделей. Один на директорию.
Seeds YAMLDescriptions + tests + column_types для seeds.
Snapshots YAMLДекларация snapshots (1.9+) + descriptions.
Macros YAMLDescriptions для 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

Преимущества:

  1. Один файл — один контекст. Все source jaffle в одном _jaffle__sources.yml. Все staging-модели jaffle в одном _jaffle__models.yml. Контекст не размазан по 5 файлам.
  2. Локальность правок. Изменили stg-модель — открыли _jaffle__models.yml, поправили description. Не нужно искать YAML по проекту.
  3. 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

Что важно:

  1. name: jaffle — это логическое имя, которое появляется в source('jaffle', 'customers'). Не обязательно совпадает со схемой в БД.
  2. schema: raw_jaffle — физическая схема. Может отличаться от dbt-логического имени.
  3. freshness — мониторинг. Если данные в customers старше 24 часов — dbt source freshness упадёт.
  4. loaded_at_field — какая колонка показывает «когда строка попала в warehouse» (а не время в исходной системе).
  5. Тесты на 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-фич:

  1. description: | — pipe позволяет многострочное описание. Markdown поддерживается.
  2. config: — конфигурация модели прямо в YAML. Альтернатива {{ config(...) }} в SQL. В 1.9+ это рекомендованный путь.
  3. tags — для node selection (dbt run --select tag:staging).
  4. columns — описание + тесты на каждую колонку.
  5. 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") }}'

Преимущества:

  1. Reuse. customer_id description пишется один раз, используется в 10 моделях.
  2. Markdown-форматирование (code blocks, ссылки, списки) работает.
  3. Лучше для длинных описаний — отдельный .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, добавляешь запись. Не нужно искать.


Что НЕ делать

  1. Один schema.yml на 5000 строк. Старая практика 2018-2019. Сейчас антипаттерн. Невозможно навигировать, git diff показывает изменения сразу в 50 моделях.

  2. YAML рядом с каждой моделью. stg_jaffle__customers.yml рядом с stg_jaffle__customers.sql. Допустимо, но в большом проекте — хаос: 200 YAML вместо 20.

  3. YAML без descriptions. Только name: и tests: — но без description. Через год невозможно понять, что эта модель.

  4. Дублирование описания. То же самое описание в YAML и в SQL комментарии. Источник правды должен быть один — обычно YAML.

  5. YAML с разными версиями. version: 1 и version: 2 в разных файлах. С 2020 года стандарт — version: 2. Всегда так.

  6. Длинные 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. Что произойдёт:

  1. dbt парсит YAML, обнаруживает source и две модели.
  2. Запускает модели по DAG.
  3. Запускает тесты: 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.


Ключевые выводы

  1. YAML — это метаданные, параллельный слой к SQL. Не код, а описания + тесты + конфиги.
  2. Convention: один YAML на директорию с именем _<group>__<type>.yml. Подчёркивание в начале — чтобы YAML был сверху в листинге.
  3. Типы YAML: sources, models, seeds, snapshots, macros, exposures. Каждый со своей секцией top-level (sources:, models:, seeds:).
  4. В sources YAML: декларация source + freshness + loaded_at_field + tests на колонках.
  5. В models YAML: descriptions + tests + config + columns. relationships тест проверяет FK.
  6. Doc blocks (.md) для длинных descriptions. {% docs name %}...{% enddocs %}, ссылаются через {{ doc('name') }} в YAML.
  7. Антипаттерн — schema.yml на весь проект (старое наследие) или YAML рядом с каждой моделью (хаос).
YAML в большом проекте
Проверка знанийKnowledge check
Команда увеличила проект с 10 моделей до 80, и старый `schema.yml` на 1200 строк стал невыносим. Что делать?
ОтветAnswer
Разделить YAML по группам — **один YAML на директорию**.\n\nПлан рефакторинга:\n\n1. **Сгруппировать модели** в директории по слоям и доменам:\n - `models/staging/<source>/` — staging по source.\n - `models/intermediate/<domain>/` — intermediate по домену.\n - `models/marts/<domain>/` — marts по домену.\n\n2. **Создать YAML в каждой директории**: `_<group>__models.yml`.\n\n3. **Перенести записи** из старого schema.yml в соответствующие YAML. Каждый `- name: stg_jaffle__customers` -> `_jaffle__models.yml`. Каждый `- name: fct_orders` -> `_core__models.yml`.\n\n4. **Удалить старый schema.yml** после миграции.\n\n5. **Source-декларации** — отдельно в `_<group>__sources.yml` в соответствующей staging-директории.\n\nПреимущества:\n- В каждом YAML 5-15 моделей, легко навигировать.\n- Code review показывает изменение одного файла на одну тематику.\n- Новый member видит structure из имён директорий.\n\nМиграцию обычно делают одним PR — `dbt parse` проверяет, что все записи на месте.
Проверка знанийKnowledge check
Зачем подчёркивание в начале имени `_jaffle__models.yml`? Без него работает же.
ОтветAnswer
Технически — работает. dbt парсит **любые `.yml`** в models/ независимо от имени. Подчёркивание — это **сортировочная конвенция**, не функциональная.\n\nПочему сообщество выбрало подчёркивание:\n\n1. **Сортировка ASCII.** Подчёркивание (`_`) идёт раньше букв в ASCII-сортировке. В `ls` и в IDE-листинге YAML-файлы появляются **сверху** директории, до SQL-моделей.\n\n2. **Визуальный паттерн.** Открыл директорию, увидел `_jaffle__sources.yml` и `_jaffle__models.yml` сверху — сразу понял: метаданные тут.\n\n3. **Group by convention.** Все `_*`-файлы — конфиги. Все остальные — код. Мысленно разделять проще.\n\n4. **Совместимость с другими языками.** В Python `_private` — это тоже модули, начинающиеся с подчёркивания: convention «не основная логика».\n\nЭто не дбт-специфичное, это unix-стиль. Без него работает, но team-members ожидают подчёркивание — и нарушение convention создаёт когнитивную нагрузку при code review.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. В проекте старый `schema.yml` на 1500 строк описывает 80 моделей. Что делать в современном dbt-проекте?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4