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
Три типа источников:
| Тип | Формат | Использование |
|---|---|---|
| Hub | package: <org>/<name>, version: x.y.z | Стандартные packages от dbt Labs / community с хаба hub.getdbt.com. |
| Git | git: <url>, revision: <tag> | Любой git-репозиторий: GitHub, GitLab, internal, fork. Гибкость. |
| Local | local: <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
Что происходит:
- dbt читает
packages.yml. - Для каждого пакета:
- Hub: смотрит на hub.getdbt.com, находит git URL, делает
git clone. - Git:
git clone <url> && git checkout <revision>. - Local: создаёт симлинк.
- Hub: смотрит на hub.getdbt.com, находит git URL, делает
- Скачанные пакеты лежат в
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...
Что в нём:
- Exact versions (Hub-пакетов).
- Exact commit SHA (git-пакетов) — даже если revision был tag/branch, lock-файл фиксирует commit.
- 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+)
До 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 helpers | star, pivot, unpivot, deduplicate, get_column_values, group_by |
| Хеши и keys | generate_surrogate_key, safe_add |
| Date helpers | date_spine, last_day, week_start |
| Тесты (data) | unique_combination_of_columns, expression_is_true, equal_rowcount, equality |
| Тесты на cardinality | cardinality_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 за год.
Антипаттерны
Попробуй сам
В вашем 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.
Ключевые выводы
- dbt package = переиспользуемая библиотека макросов / моделей / тестов. Подключается через
packages.yml+dbt deps. - Три источника: hub (Hub-namespace + version), git (URL + revision), local (path). Для production — обычно hub с exact version.
- package-lock.yml (1.7+) — лок-файл с exact versions и SHA. Коммитьте его в git.
- dbt_packages/ — куда скачиваются пакеты. Всегда в
.gitignore. - dbt_utils — must-have пакет: date_spine, pivot, surrogate_key, deduplicate, generic тесты.
- Conflicts: dbt deps падает с понятным сообщением (1.10 улучшено). Resolve через обновление версий.
- Use macros from packages через namespace:
{{ dbt_utils.foo() }}. Без префикса — конфликт с локальными макросами. - Версии — exact tag (не branch) в production. Range — только верхний bound должен быть.