Learning Platform
Глоссарий Troubleshooting
Урок 17.01 · 20 мин
Начальный
Packagespackages.ymldbt depsHubpackage-lock

packages.yml: подключение dbt-packages

dbt-проект редко строится из нуля. dbt packages — это переиспользуемые библиотеки макросов, моделей, тестов, написанные сообществом и dbt Labs. Самые известные:

  • dbt_utils (от dbt Labs) — стандартный набор helper-макросов (date_spine, pivot, surrogate_key, deduplicate).
  • dbt_expectations (от Calogica) — тесты в стиле Great Expectations (expect_column_values_to_be_between и т.д.).
  • codegen — генерация source/model boilerplate.
  • dbt_external_tables — работа с external tables (S3, Parquet).
  • dbt_audit_helper — сравнение результатов между branches.

Эти пакеты — это код dbt (макросы, модели, тесты), который тяну как dependency. Один файл packages.yml + dbt deps, и в проекте появляются десятки готовых макросов.


packages.yml — анатомия

packages.yml лежит в корне dbt-проекта (рядом с dbt_project.yml):

# packages.yml
packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0

  - package: calogica/dbt_expectations
    version: 0.10.4

  - git: "https://github.com/dbt-labs/dbt_codegen.git"
    revision: 0.13.1

  - local: ../shared_dbt_macros

Три типа источников:

ТипФорматИспользование
Hubpackage: <org>/<name>, version: x.y.zСтандартные packages от dbt Labs / community с хаба hub.getdbt.com.
Gitgit: <url>, revision: <tag>Любой git-репозиторий: GitHub, GitLab, internal, fork. Гибкость.
Locallocal: <path>Локальный путь к package на диске. Monorepo, shared modules.

Hub-пакеты

hub.getdbt.com — официальный registry dbt-пакетов. На нём — десятки тысяч пакетов, проверены community.

packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0

Что значит:

  • dbt-labs — namespace (организация в GitHub).
  • dbt_utils — имя package.
  • version: 1.3.0 — exact version. Также допустимы:
    • version: [">=1.0.0", "менее 2.0.0"] — range.
    • version: 1.3.0 — exact (рекомендуется в production).

После dbt deps пакет скачается в dbt_packages/dbt_utils/.

В Hub URL обычно совпадает с GitHub: dbt-labs/dbt_utils -> https://github.com/dbt-labs/dbt-utils. Hub — это просто metadata layer над git.


Git-пакеты

Если пакета нет на хабе или нужен fork:

packages:
  - git: "https://github.com/dbt-labs/dbt_codegen.git"
    revision: 0.13.1

  - git: "https://github.com/your-org/internal-dbt-macros.git"
    revision: main
    subdirectory: macros_module

  - git: "[email protected]:your-org/private-repo.git"
    revision: v2.5.0

revision — это git ref: tag, branch, commit SHA. Рекомендуется tag, не branch — для воспроизводимости. Branch может измениться, tag — не должен.

subdirectory — если package живёт не в корне репозитория. Например, у вас monorepo с несколькими dbt-packages: subdirectory: packages/finance_macros.

Private repos через SSH ([email protected]:...) или HTTPS с token. dbt deps выполняет git clone — работает через стандартные git credentials.


Local-пакеты

Для monorepo или shared module внутри одной компании:

packages:
  - local: ../shared_dbt_macros
  - local: /Users/levoely/Projects/internal_dbt_lib

dbt симлинкует локальный путь в dbt_packages/. Изменения в shared_dbt_macros сразу видны в основном проекте без dbt deps (но всё равно рекомендуется dbt clean && dbt deps после крупных изменений).

Удобно для разработки общих макросов: правишь в одном месте, сразу тестируешь в нескольких проектах.


dbt deps — установка пакетов

После записи packages.yml:

dbt deps

Что происходит:

  1. dbt читает packages.yml.
  2. Для каждого пакета:
    • Hub: смотрит на hub.getdbt.com, находит git URL, делает git clone.
    • Git: git clone <url> && git checkout <revision>.
    • Local: создаёт симлинк.
  3. Скачанные пакеты лежат в dbt_packages/:
jaffle_shop/
  dbt_project.yml
  packages.yml
  package-lock.yml    ← lockfile (1.7+)
  models/
  dbt_packages/        ← скачанные пакеты, в .gitignore
    dbt_utils/
      dbt_project.yml
      macros/
      models/
    dbt_expectations/
      ...

После dbt deps все макросы / модели / тесты из пакетов доступны в проекте через {{ dbt_utils.foo() }} или {{ dbt_expectations.bar() }}.

dbt_packages/ всегда в .gitignore — это generated content, version-locked через package-lock.yml.


package-lock.yml

С dbt 1.7+ dbt создаёт package-lock.yml — лок-файл, аналог package-lock.json (npm) или Gemfile.lock (Ruby).

# package-lock.yml (генерируется автоматически)
packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0
  - package: calogica/dbt_expectations
    version: 0.10.4
  - git: "https://github.com/dbt-labs/dbt_codegen.git"
    revision: 33fa64b9b09e8ef5f29d8a8a6b48a0a48dc3d29b   # exact commit SHA
sha1_hash: 8a2f3...

Что в нём:

  1. Exact versions (Hub-пакетов).
  2. Exact commit SHA (git-пакетов) — даже если revision был tag/branch, lock-файл фиксирует commit.
  3. sha1_hash — хеш всего lock-файла для целостности.

package-lock.yml в git-репозитории — да, его коммитят. Это гарантирует, что все (CI, коллеги) получат те же версии при dbt deps.

dbt deps              # читает lock, если есть; иначе резолвит packages.yml
dbt deps --upgrade    # игнорирует lock, обновляет до последних версий
dbt deps --add-package dbt-labs/[email protected]  # добавить пакет (1.7+)
NOTE

До 1.7 lock-файла не было. Каждый запуск dbt deps мог тянуть разные patch-версии (если был range). 1.7+ это исправляет — стандарт modern dbt workflows.


Конкретный пример с dbt_utils

# packages.yml
packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0
dbt deps
# Installing dbt-labs/dbt_utils
#   Installed from version 1.3.0

Теперь в любой модели:

-- models/marts/dim_dates.sql
{{ dbt_utils.date_spine(
    datepart="day",
    start_date="cast('2020-01-01' as date)",
    end_date="cast('2030-12-31' as date)"
) }}

{{ dbt_utils.date_spine(...) }} — макрос из пакета. Префикс dbt_utils. обязательный — это namespace, чтобы не было конфликтов с локальными макросами.

-- Surrogate key через dbt_utils
SELECT
    {{ dbt_utils.generate_surrogate_key(['customer_id', 'product_id']) }} AS sk,
    customer_id,
    product_id,
    amount
FROM orders

И в тестах:

# _models.yml
models:
  - name: fct_orders
    data_tests:
      - dbt_utils.unique_combination_of_columns:
          combination_of_columns:
            - order_id
            - line_id

Это уже доступные тесты после установки пакета. Не нужно писать самому.


Что в dbt_utils (квик-обзор)

dbt_utils — must-have пакет, ставится в 95% production-проектов. Что внутри:

КатегорияМакросы
SQL helpersstar, pivot, unpivot, deduplicate, get_column_values, group_by
Хеши и keysgenerate_surrogate_key, safe_add
Date helpersdate_spine, last_day, week_start
Тесты (data)unique_combination_of_columns, expression_is_true, equal_rowcount, equality
Тесты на cardinalitycardinality_equality, fewer_rows_than

Подробнее в уроке 15.2.


Конфликты версий и dependencies

Пакеты могут зависеть от других пакетов. Например, dbt_expectations зависит от dbt_utils. Если вы укажете:

packages:
  - package: dbt-labs/dbt_utils
    version: 1.0.0   # старая
  - package: calogica/dbt_expectations
    version: 0.10.4   # требует dbt_utils >= 1.2.0

dbt deps упадёт:

ERROR: Version conflict for dbt_utils:
  required by dbt_expectations 0.10.4: >=1.2.0,<2.0.0
  user specified: 1.0.0

Решение: обновить версию dbt_utils в packages.yml до совместимой.

В 1.10 dbt улучшил error messages для conflicts — теперь сразу видно, какой пакет требует какой range.


Что лежит в dbt_packages/

После dbt deps:

dbt_packages/
  dbt_utils/
    dbt_project.yml      ← мини-проект пакета
    macros/              ← макросы (главное)
    models/              ← опциональные модели
    tests/               ← тесты
    integration_tests/   ← integration тесты (для разработчиков пакета)
    README.md
  dbt_expectations/
    macros/
    ...

Каждый пакет — это отдельный dbt-проект. У него свой dbt_project.yml, свои models, macros, tests. dbt видит их и добавляет в основной проект.

dbt_packages/ в .gitignore:

# .gitignore
target/
dbt_packages/
logs/
.user.yml

Версии фиксируются package-lock.yml, не файлами. Дискспейс меньше, repo чище.


Использование макроса из пакета

Прямой вызов:

SELECT * FROM {{ ref('orders') }}
WHERE order_date BETWEEN
  '{{ dbt_utils.dateadd(datepart="day", interval=-30, from_date_or_timestamp="current_date") }}'
  AND CURRENT_DATE

После dbt compile Jinja развернётся в адаптер-специфичный SQL:

-- В DuckDB:
SELECT * FROM main.orders
WHERE order_date BETWEEN
  '2026-04-19'
  AND CURRENT_DATE

Или (для Postgres):

SELECT * FROM main.orders
WHERE order_date BETWEEN
  (current_date + (-30 || ' day')::interval)
  AND CURRENT_DATE

Это и есть смысл packages: dbt_utils.dateadd работает кросс-warehouse. На каждом адаптере свой SQL, но макрос один.


Когда не нужен пакет

Пакет — это dependency. Каждая dependency — это:

  • Доп. время dbt deps в CI.
  • Возможность conflicts с другими пакетами.
  • Доверие чужому коду.
  • Maintenance burden, когда пакет deprecated.

Если нужен один маленький макрос — может, проще написать его локально. Например, nullif_zero (превращает 0 в NULL) — это 3 строки кода:

-- macros/nullif_zero.sql
{% macro nullif_zero(col) %}
    NULLIF({{ col }}, 0)
{% endmacro %}

Не нужен dedicated package, если тащит 20 ненужных функций.

Что обычно стоит установить:

  • dbt_utils — обязательно, используется почти в каждом проекте.
  • dbt_expectations — если делаете strict data quality testing.
  • codegen — для quick scaffolding в раннем проекте.

Что обычно не нужно:

  • Узкоспециализированные пакеты «один use-case». Лучше write inline.
  • Пакеты с одним maintainer’ом и без updates за год.

Антипаттерны

Антипаттерны packages.yml

Попробуй сам

В вашем dbt-проекте создайте packages.yml:

packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0

Запустите:

dbt deps

Проверьте структуру:

ls dbt_packages/dbt_utils/
ls dbt_packages/dbt_utils/macros/
cat package-lock.yml

Используйте макрос из dbt_utils. Создайте models/test_macros.sql:

WITH dates AS (
    {{ dbt_utils.date_spine(
        datepart="day",
        start_date="cast('2026-01-01' as date)",
        end_date="cast('2026-01-10' as date)"
    ) }}
)

SELECT date_day FROM dates ORDER BY date_day

Запустите dbt run --select test_macros. Откройте результаты в DuckDB — увидите 10 дней.

Бонус: добавьте dbt_expectations:

packages:
  - package: dbt-labs/dbt_utils
    version: 1.3.0
  - package: calogica/dbt_expectations
    version: 0.10.4

dbt deps. Проверьте, что dbt_expectations появился в dbt_packages/. Также проверьте, что в package-lock.yml зафиксированы exact versions.


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

  1. dbt package = переиспользуемая библиотека макросов / моделей / тестов. Подключается через packages.yml + dbt deps.
  2. Три источника: hub (Hub-namespace + version), git (URL + revision), local (path). Для production — обычно hub с exact version.
  3. package-lock.yml (1.7+) — лок-файл с exact versions и SHA. Коммитьте его в git.
  4. dbt_packages/ — куда скачиваются пакеты. Всегда в .gitignore.
  5. dbt_utils — must-have пакет: date_spine, pivot, surrogate_key, deduplicate, generic тесты.
  6. Conflicts: dbt deps падает с понятным сообщением (1.10 улучшено). Resolve через обновление версий.
  7. Use macros from packages через namespace: {{ dbt_utils.foo() }}. Без префикса — конфликт с локальными макросами.
  8. Версии — exact tag (не branch) в production. Range — только верхний bound должен быть.
dbt-utils: глубокий разбор
Проверка знанийKnowledge check
Команда добавила dbt_utils в packages.yml, запустила dbt deps. В CI на следующей неделе deploy упал с ошибкой 'macro generate_surrogate_key not found'. Что произошло?
ОтветAnswer
Скорее всего проблема в **выпавшей зависимости** или **пропущенном dbt deps в CI**:\n\n1. **CI не запускает `dbt deps`.** Это обязательно перед `dbt run` или `dbt build`. Пайплайн должен быть: `dbt deps && dbt build`.\n\n2. **`dbt_packages/` закоммичен в git, но не `package-lock.yml`.** Старый антипаттерн: коммитят `dbt_packages/`, не коммитят lock. Решение: `dbt_packages/` в `.gitignore`, `package-lock.yml` в git.\n\n3. **Конфликт версий между `packages.yml` и lock-файлом.** Кто-то обновил `packages.yml`, но не пере-сгенерил lock. Решение: `dbt deps --upgrade` локально, закоммитить новый lock.\n\n4. **CI кеширует `dbt_packages/` из старого state.** Кеш есть, но устаревший. Решение: `dbt clean` перед `dbt deps` в CI.\n\n5. **Network issue.** hub.getdbt.com был недоступен в момент deploy. Retry.\n\nПроверка:\n```bash\n# В CI:\ndbt clean\ndbt deps\nls dbt_packages/dbt_utils/macros/ | grep generate_surrogate_key\n# Должен быть найден файл\n```
Проверка знанийKnowledge check
Можно ли использовать private GitHub repo как dbt-package?
ОтветAnswer
Да, частая практика. Подключение через git с SSH или HTTPS-токеном:\n\n**Вариант 1 — SSH**:\n\n```yaml\npackages:\n - git: "[email protected]:your-org/private-dbt-macros.git"\n revision: v1.2.0\n```\n\nРаботает, если у пользователя `dbt deps` есть SSH-ключ с доступом к репо. На локальной машине — обычный `~/.ssh/id_rsa`. В CI — добавить deploy key или secret.\n\n**Вариант 2 — HTTPS с PAT**:\n\n```yaml\npackages:\n - git: "https://{{ env_var('GITHUB_TOKEN') }}@github.com/your-org/private-dbt-macros.git"\n revision: v1.2.0\n```\n\nЗдесь PAT берётся из env var `GITHUB_TOKEN`. Удобно для CI (`GITHUB_TOKEN` доступен в GitHub Actions автоматически).\n\n**Best practices для private packages**:\n\n1. **Версионируйте через tags**, не branch. v1.0.0 — стабильный, main — может ломаться.\n2. **Один private package на компанию**. Не плодите. Общие internal macros — в одном repo.\n3. **Документируйте README**: какие макросы, как использовать, breaking changes по версиям.\n4. **CI с автотестами**: integration tests в самом package-репо, чтобы не сломать downstream-проекты.\n5. **Semantic versioning**: major.minor.patch. Breaking changes — major version up.

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

Результат: 0 из 0
Аналитический
Вопрос 1 из 5. Команда добавила `dbt-labs/dbt_utils` в packages.yml, запустила dbt deps локально. В CI deploy упал: 'macro generate_surrogate_key not found'. Что могло быть?

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

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

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

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