Когда мы установили dbt-utils или dbt-jaffle-shop через packages.yml, в проект приходит готовый набор моделей, тестов и sources — но эти sources указывают на схему/базу, которая есть у автора пакета, а не у тебя. Чтобы заставить пакетные модели читать из твоего warehouse, нужно переопределить source.
В этом уроке разберём, как это работает, и заодно дополнительные тонкости: schema/database override на уровне проекта, meta-поля и tags.
Зачем переопределять source
Простой сценарий: ты установил демо-package dbt-jaffle-shop, который ожидает source с именем jaffle_shop в схеме dbt_jaffle_shop_raw. У тебя в DuckDB raw-данные лежат в main, в файле jaffle_shop.duckdb. Без override модели пакета будут компилироваться в FROM dbt_jaffle_shop_raw.customers и падать с Catalog Error.
Решение: переопределить source в своём _sources.yml.
Package декларирует source со своими database/schema. Проект использует source через ref/select, но физическая таблица лежит в другом месте. Override решает конфликт без форка пакета.
Синтаксис override
В своём YAML добавляешь источник с тем же name, что и в пакете, плюс ключ overrides:, указывающий имя пакета:
version: 2
sources:
- name: jaffle_shop
overrides: dbt_jaffle_shop_pkg
database: jaffle_shop
schema: main
tables:
- name: orders
- name: customers
- name: payments
Ключевая магия:
overrides: dbt_jaffle_shop_pkg— говорит dbt: “это не отдельный source, это переопределение того, что декларирует пакетdbt_jaffle_shop_pkg”.- Поля
database,schemaподменяют пакетные значения. - Поле
tablesтоже можно переопределить — например, поменятьidentifierотдельных таблиц.
После такого override все модели пакета, которые используют source('jaffle_shop', 'orders'), начнут читать из jaffle_shop.main.orders (то есть из твоего warehouse), а не из dbt_jaffle_shop_pkg’овского dbt_jaffle_shop_raw.orders.
Что можно переопределить
Через overrides можно подменить почти всё, что декларирует пакет:
sources:
- name: jaffle_shop
overrides: dbt_jaffle_shop_pkg
# Уровень source
database: my_db
schema: my_schema
loader: my_loader
loaded_at_field: my_loaded_at
freshness:
warn_after: { count: 6, period: hour }
error_after: { count: 24, period: hour }
meta:
owner: data-platform-team
# Уровень отдельных таблиц
tables:
- name: orders
identifier: real_orders_table # имя в warehouse
loaded_at_field: dbt_loaded_at # подменяем для конкретной таблицы
tags: [pii, critical]
Если поле не указано в override — берётся из пакетной декларации. Это и есть смысл “override”: ты подменяешь только то, что отличается, не дублируешь весь YAML.
Schema override на уровне проекта
Помимо source-override, есть более общий механизм — schema override. Он работает не на sources, а на моделях. dbt по умолчанию строит модели в схеме target.schema (из profiles.yml). Можно настроить, чтобы модели в разных папках уходили в разные схемы.
В dbt_project.yml:
models:
jaffle_shop:
staging:
+schema: staging # модели здесь идут в <target_schema>_staging
marts:
core:
+schema: marts # модели здесь идут в <target_schema>_marts
Если target.schema = analytics, то реально модели окажутся в analytics_staging и analytics_marts. Это полезно для организации больших проектов, но к sources напрямую не относится — sources не зависят от target.schema, они полностью описаны в _sources.yml.
+schema в dbt_project.yml — это суффикс, а не полное имя. dbt добавляет его к target.schema через нижнее подчёркивание. Поведение по умолчанию: generate_schema_name macro комбинирует. Можно переопределить эту macro, но junior’у пока не нужно — на старте достаточно понимать, что schema name = target.schema + _ + custom_schema (если указан).
Database override на уровне проекта
Аналогично schema есть +database:
models:
jaffle_shop:
marts:
+database: analytics_prod # модели здесь идут в другую базу
Используется реже. На DuckDB вообще нет смысла менять database из-под dbt — база = файл, и dbt не умеет открывать сразу несколько файлов без ATTACH. На Snowflake/BigQuery полезно: например, mart-модели в prod_analytics, staging в prod_staging.
meta: и tags: для organization
Source-декларация поддерживает два важных поля — meta: и tags:. Они не влияют на компиляцию, но важны для organization, документации и автоматизации.
sources:
- name: stripe
database: raw
schema: stripe
meta:
owner: payments-team
pii_level: high
contains_pii: true
tags: [pii, payments, critical]
tables:
- name: charges
meta:
retention_days: 365
tags: [billing]
meta— произвольный словарь, доступен в Jinja черезgraph.sources['source.<project>.<name>.<table>'].meta. Применяется для custom-логики: например, autogenerated docs, alert-rules, data lineage экспорт.tags— список строк. Используется в--select tag:piiдля node selection. Можно запуститьdbt test --select tag:pii, чтобы тестировать только PII-таблицы.
В dbt 1.10+ много полей source раньше были top-level, а теперь должны быть под meta:. Например, custom-property data_owner: alice без обёртки в meta даст warning. Если видишь предупреждение Custom top-level property 'data_owner' on source — оберни в meta.
Полный пример с override
Допустим, мы используем пакет jaffle_shop от dbt Labs. Он декларирует:
# packages/dbt_jaffle_shop_pkg/models/staging/_sources.yml
sources:
- name: jaffle_shop
database: raw
schema: jaffle_shop_raw
tables:
- name: customers
- name: orders
- name: payments
У нас в проекте warehouse — DuckDB-файл ./jaffle_shop.duckdb, схема main, таблицы называются raw_customers, raw_orders, raw_payments. Чтобы пакетные модели заработали:
# models/_sources_overrides.yml
version: 2
sources:
- name: jaffle_shop
overrides: dbt_jaffle_shop_pkg
database: jaffle_shop
schema: main
tables:
- name: customers
identifier: raw_customers
- name: orders
identifier: raw_orders
- name: payments
identifier: raw_payments
Что произойдёт: модели в пакете, например stg_customers.sql, продолжают писать:
SELECT * FROM {{ source('jaffle_shop', 'customers') }}
Но dbt видит override и компилирует это в:
SELECT * FROM jaffle_shop.main.raw_customers
Пакет не нужно форкать или модифицировать. Override — это твоя локальная адаптация.
Когда override НЕ нужен
Не каждый проект использует пакеты. Если у тебя только свой _sources.yml без overrides:, ты работаешь с обычной декларацией. Override — это инструмент исключительно для тех случаев, когда чужой YAML диктует имена.
Если ты сам контролируешь source — просто меняй database/schema в своём YAML, никаких overrides не надо.
Если sources объявлены тобой — меняешь напрямую. Если приходят из пакета — нужен override. В смешанных проектах могут быть оба варианта.
Попробуй сам
Если у тебя установлен пакет dbt_utils, у него тоже есть свои тестовые sources — но они нужны только для unit-тестов внутри пакета и тебя не задевают. Для практики проще симулировать ситуацию вручную.
- Создай
models/_sources.ymlс обычной декларацией:
version: 2
sources:
- name: jaffle_shop
database: jaffle_shop
schema: main
tables:
- name: customers
-
Поменяй schema на несуществующую:
schema: nonexistent. Запустиdbt compile --select stg_customers(если у тебя есть такая модель). Увидишь, что в скомпилированном SQL появилосьnonexistent.customers, и приdbt runупадёт Catalog Error. -
Поменяй обратно
schema: main, но добавьmeta: { owner: my-team }иtags: [pii]. Запустиdbt list --select tag:pii— должна показаться твоя таблица.
Это тренирует понимание, что декларация — это просто YAML, который dbt парсит и применяет при компиляции.
Что мы поняли
Source overrides — это механизм переопределения source-декларации, когда она приходит из package. Используется ключевое поле overrides: <package_name>, остальные поля (database, schema, freshness, tables) подменяют пакетные значения. На уровне проекта дополнительно есть +schema и +database в dbt_project.yml — но они влияют на модели, а не на sources. Поля meta: и tags: дают организационные возможности: автоматизация, selection, документация.
На этом мы закрыли тему sources в junior-курсе. В следующем модуле разберём, как dbt материализует модели — view, table, ephemeral, incremental, и почему выбор стратегии критичен для производительности.