Когда что-то не работает в dbt, первый рефлекс — гуглить ошибку. Второй — должен быть «открой target/». Эта папка содержит всё, что dbt только что произвёл: финальный SQL, артефакты с метаданными, статусы запусков. Знать, что где лежит, экономит часы.
Жизненный цикл папки target/
target/ создаётся при любой команде dbt (compile, run, test, build, docs generate, …) и перезаписывается каждый раз. То, что лежит в ней после последней команды — это снэпшот этого запуска.
target/
├── compiled/ # SQL после развёртки Jinja (без CREATE TABLE обёртки)
├── run/ # тот же SQL, но обёрнутый в CREATE TABLE / CREATE VIEW
├── manifest.json # структура всего проекта: модели, тесты, sources, lineage
├── catalog.json # после `dbt docs generate`: типы колонок, реальные имена в БД
├── run_results.json # после каждого dbt run/test/build: статусы и тайминги
├── partial_parse.msgpack # кеш парсинга проекта
├── graph.gpickle # сериализованный граф зависимостей
└── semantic_manifest.json # для семантических метрик
Compiled и run — это твой SQL глазами dbt. Manifest и run_results — машинно-читаемые артефакты для интеграций.
target/compiled/ — финальный SQL без обёртки
Здесь живёт выход Jinja-компиляции: твой SQL, в котором все {{ ref() }}, {{ source() }}, {% set %}, {% for %}, макросы — развёрнуты в строки и значения.
Структура зеркалит models/:
target/compiled/jaffle_shop/
├── models/
│ ├── staging/
│ │ ├── stg_jaffle__customers.sql
│ │ └── stg_jaffle__orders.sql
│ ├── intermediate/
│ │ └── int_order_items_pivoted.sql
│ └── marts/
│ ├── customers.sql
│ └── revenue_daily.sql
├── tests/
│ └── unique_customers_customer_id.sql
└── seeds/...
Открой target/compiled/jaffle_shop/models/marts/customers.sql:
-- было в models/marts/customers.sql:
-- select c.customer_id, c.first_name, ...
-- from {{ ref('stg_jaffle__customers') }} c
-- left join {{ ref('int_order_items_pivoted') }} o ...
-- стало в target/compiled/...:
select c.customer_id, c.first_name, ...
from "jaffle_shop"."main"."stg_jaffle__customers" c
left join "jaffle_shop"."main"."int_order_items_pivoted" o ...
Это главный артефакт для дебага. Скопируй файл целиком в DuckDB shell:
$ duckdb jaffle_shop.duckdb
D> .read target/compiled/jaffle_shop/models/marts/customers.sql
Если SQL работает — проблема в материализации (table vs view, конфиги). Если падает — проблема в самом SQL.
Важно: target/compiled/ не содержит CREATE TABLE — это голый SELECT .... Чтобы увидеть, как именно dbt создаёт таблицу, смотри target/run/.
target/run/ — финальный SQL с CREATE-обёрткой
То же самое, но обёрнутое в нужный DDL по конфигу материализации:
-- target/run/jaffle_shop/models/marts/customers.sql
create or replace table "jaffle_shop"."main"."customers" as (
select c.customer_id, c.first_name, ...
from "jaffle_shop"."main"."stg_jaffle__customers" c
left join "jaffle_shop"."main"."int_order_items_pivoted" o ...
);
Для view-моделей будет CREATE OR REPLACE VIEW .... Для incremental — INSERT INTO ... WHERE NOT EXISTS ... или MERGE.
Когда смотреть сюда:
- ты подозреваешь, что dbt оборачивает не в то, что ожидал
- видишь ошибку «
materialized viewnot supported» — а ты конфигурил какtable, и хочешь понять, что dbt считает - хочешь увидеть точный синтаксис INSERT для инкрементальной модели
target/manifest.json — главный артефакт проекта
manifest.json — это сериализованный весь твой проект: каждая модель, тест, source, snapshot, exposure, со всеми зависимостями, конфигами, описаниями.
Структура (упрощённо):
{
"metadata": {
"dbt_version": "1.10.2",
"generated_at": "2026-05-19T14:35:00Z",
"project_name": "jaffle_shop"
},
"nodes": {
"model.jaffle_shop.customers": {
"name": "customers",
"resource_type": "model",
"schema": "main",
"database": "jaffle_shop",
"config": { "materialized": "table", "tags": ["mart"] },
"depends_on": {
"nodes": [
"model.jaffle_shop.stg_jaffle__customers",
"model.jaffle_shop.int_order_items_pivoted"
]
},
"columns": { "customer_id": { ... } },
"compiled_code": "select ..."
}
},
"sources": { "source.jaffle_shop.jaffle.customers": { ... } },
"macros": { ... },
"tests": { ... }
}
Кто его использует:
dbt list,dbt docs serve— читают, чтобы построить lineage и страницы.- CI с
--state ./prod-manifest— сравнивает с baseline дляstate:modified. - dbt Explorer / dbt Cloud — лень-парсит для UI.
- Внешние инструменты (Datafold, Atlan, Castor) — для каталога метаданных.
Junior туда заглядывает редко, но полезно знать: «если что-то странное с lineage, открой manifest.json, найди узел, посмотри depends_on.nodes».
target/run_results.json — статусы последнего запуска
После каждой команды (run, test, build, seed, …) dbt пишет сюда результат каждого узла:
{
"metadata": { "generated_at": "2026-05-19T14:35:01Z" },
"args": {
"command": "build",
"select": ["stg_orders+"],
"target": "dev"
},
"results": [
{
"unique_id": "model.jaffle_shop.stg_orders",
"status": "success",
"execution_time": 0.083,
"message": null,
"thread_id": "Thread-2",
"timing": [
{ "name": "compile", "started_at": "...", "completed_at": "..." },
{ "name": "execute", "started_at": "...", "completed_at": "..." }
]
},
{
"unique_id": "test.jaffle_shop.unique_orders_order_id.abc123",
"status": "fail",
"execution_time": 0.042,
"message": "Got 3 results, configured to fail if != 0",
"failures": 3
},
{
"unique_id": "model.jaffle_shop.customers",
"status": "skipped",
"message": "Upstream test failed"
}
]
}
Это источник правды для dbt retry: команда читает этот файл, находит все узлы со status: error или status: skipped, и перезапускает только их + их downstream.
Также используется в CI для метрик: «сколько моделей упало», «сколько строк в среднем в таблицах», «топ-10 самых медленных моделей».
target/catalog.json — только после docs generate
Этот файл не появляется после dbt run. Он создаётся только при dbt docs generate, и содержит реальные имена таблиц, типы колонок, статистики из information_schema warehouse:
{
"nodes": {
"model.jaffle_shop.customers": {
"metadata": {
"type": "BASE TABLE",
"schema": "main",
"name": "customers",
"database": "jaffle_shop"
},
"columns": {
"customer_id": {
"type": "INTEGER",
"index": 1,
"name": "customer_id"
},
"first_name": { "type": "VARCHAR", "index": 2 }
},
"stats": {
"row_count": { "value": 1000 },
"bytes": { "value": 24576 }
}
}
}
}
Используется dbt docs serve для отображения «реальных» колонок и количества строк в каталоге. Если catalog.json устаревший — на странице будут несоответствия (модель уже изменилась, но catalog показывает старые типы).
partial_parse.msgpack — кеш парсинга
В большом проекте полный парсинг (partial_parse: false) занимает 10-30 секунд. Чтобы быстрее, dbt сохраняет частичный парсинг — какие файлы он уже разобрал, какие конфиги вытащил, и в следующем запуске пере-парсит только изменённые.
Этот файл бинарный (msgpack), напрямую его не читают. Но если у тебя странные «фантомные» ошибки про конфиг, который ты вроде бы исправил — попробуй dbt clean (удаляет target/, включая partial_parse) и запусти заново. Иногда кеш протухает.
Чтобы отключить partial parsing: dbt --no-partial-parse run.
graph.gpickle — DAG в pickle
Сериализованный граф зависимостей в формате Python pickle. Используется внутренне для быстрого вычисления селекторов (особенно +model+, state:modified+). Junior сюда не лезет.
Карта «что куда смотреть»
Большинство вопросов junior решаются открытием правильного файла в target/. Гуглить — третий шаг.
Практический пример: дебаг «модель не запускается»
Ситуация: ты пишешь модель, запускаешь dbt run --select my_model, получаешь:
Error: Compilation Error in model my_model (models/my_model.sql)
'undefined macro' encountered
Шаги:
-
Открой
target/compiled/jaffle_shop/models/my_model.sql.- Если файл там есть и SQL выглядит нормально — проблема была в
target/run/обёртке. - Если файла нет — компиляция вообще не дошла; смотри
logs/dbt.log(об этом следующий урок).
- Если файл там есть и SQL выглядит нормально — проблема была в
-
Если SQL в
compiled/корявый — посмотри, какие{{ }}развернулись не так. Возможные причины:- macro имеется в проекте, но
dbt depsне запускался (пакет не подтянут) - макрос определён в другом месте, имя коллизит
- опечатка в имени макроса
- macro имеется в проекте, но
-
Если SQL валидный, но
dbt runпадает на DDL — откройtarget/run/jaffle_shop/models/my_model.sql, увидишьCREATE OR REPLACE TABLE .... Скопируй в DuckDB shell и проверь ошибку базы. -
Если что-то странное с
state:modified— откройmanifest.jsonиprod-manifest/manifest.json, сравни узел, который должен быть «modified», по полямraw_codeилиconfig.
.gitignore — что НЕ коммитим
target/ — не в git. Тысячи мелких файлов, перезаписываются каждый запуск, никто их не должен видеть, кроме тебя локально и CI:
# .gitignore (стандарт для dbt-проекта)
target/
dbt_packages/
logs/
.user.yml
profiles.yml # секреты
Единственное исключение: manifest.json в CI коммитят в специальный «production-artifacts»-объект (S3, GitHub artifact) — это нужно для state:modified в PR-CI.
Попробуй сам
В Jaffle Shop:
-
Запусти
dbt compile --select customers. Откройtarget/compiled/jaffle_shop/models/marts/customers.sql. Найди{{ ref('stg_jaffle__customers') }}в исходнике — посмотри, во что оно развернулось. -
Запусти
dbt run --select customers. Откройtarget/run/jaffle_shop/models/marts/customers.sql. Сравни с compiled — увидишьcreate or replace table ...обёртку. -
Запусти
dbt build. Откройtarget/run_results.json. Найди вresultsсекции status каждого узла. Сравни числоsuccess,fail,skippedс выводом терминала. -
Открой
target/manifest.json, найди объектnodes['model.jaffle_shop.customers']. Посмотри егоdepends_on.nodes— это зависимости черезref(). -
Запусти
dbt docs generateи откройtarget/catalog.json. Найдиnodes['model.jaffle_shop.customers'].columns— увидишь типы реальных колонок из warehouse.
Чек-лист
target/compiled/<model>.sql— финальный SELECT, копируй в shell для дебага.target/run/<model>.sql— то же + CREATE-обёртка.target/manifest.json— структура всего проекта; для CI, lineage, интеграций.target/run_results.json— статусы последнего запуска; для retry и метрик.target/catalog.json— реальные колонки из warehouse; только послеdocs generate.target/partial_parse.msgpack— кеш парсинга;dbt cleanесли протухло.target/всегда в.gitignore.- В CI manifest.json от main-билда сохраняется в S3 как baseline для PR-CI.