dbt docs generate и serve
В предыдущих уроках мы писали description и doc blocks. Теперь — как превратить их в работающий UI, где аналитики ищут модели, читают descriptions, смотрят DAG-граф зависимостей.
dbt не имеет «облачного UI» из коробки — это локальная статическая веб-страница, которую генерирует команда dbt docs generate, а потом раздаёт dbt docs serve (или хостит на любом static-сервере).
В этом уроке — что генерится, что в UI, типичные паттерны деплоя.
Две команды: generate и serve
dbt docs generate # генерит документацию
dbt docs serve # запускает локальный веб-сервер для просмотра
Это две независимые операции. generate собирает данные, serve показывает их в браузере.
В CI/CD типично: dbt docs generate -> push артефактов в S3 / GitHub Pages / Netlify. dbt docs serve — для локальной разработки.
Что делает dbt docs generate
Под капотом — три шага:
В итоге в папке target/ появляются файлы:
target/
manifest.json ← структура проекта (models, dependencies, descriptions)
catalog.json ← actual schemas из warehouse
run_results.json ← результаты последнего run/test (если был)
graph.gpickle ← Python-pickle графа (для internal dbt операций)
partial_parse.msgpack ← cache парсинга
compiled/ ← скомпилированный SQL каждой модели
run/ ← SQL запросы, которые выполнялись
index.html ← статический UI (это что показывает dbt docs serve)
Размер target/ обычно — десятки МБ для проекта на 100 моделей. Для огромных проектов (1000+ моделей) — может быть 100+ МБ.
Что делает dbt docs serve
После dbt docs generate запускаете:
dbt docs serve
# Serving docs at 0.0.0.0:8080
# Press Ctrl+C to exit.
Открывается локальный HTTP-сервер на порту 8080. Заходите в браузере на http://localhost:8080 — видите UI.
Под капотом — это обычный static file server. Раздаёт файлы из target/. Никакой динамики, никаких запросов в warehouse — всё уже в manifest.json и catalog.json.
Поэтому dbt docs serve можно заменить на любой static-сервер:
cd target && python -m http.server 8080
# или
cd target && npx serve
Это значит — легко хостится на GitHub Pages / Netlify / S3 + CloudFront / любом nginx.
Структура UI
При открытии UI:
Что на странице модели
Открыв fct_orders в UI, видим:
- Header: имя модели, тип (model / seed / snapshot / source), путь к файлу.
- Description: rendered markdown из YAML / doc block.
- Columns: таблица с колонками — name, type, description, tests.
- Details (collapsible): config (materialized, schema), tags, meta.
- Code: исходный SQL (raw) + compiled SQL.
- Tests: список тестов на этой модели.
- Lineage graph: визуализация DAG — кто upstream, кто downstream.
Это must-have для аналитика: открыл модель -> за 30 секунд понял что это, какие колонки, откуда приходит, кто использует.
Lineage graph — самая ценная часть
Граф зависимостей — главная фича dbt docs. Кнопка справа внизу View Lineage Graph.
В графе:
- Зелёные узлы — sources.
- Синие узлы — models.
- Жёлтые узлы — seeds.
- Фиолетовые узлы — snapshots.
- Розовые узлы — exposures.
Линии — ref() / source() зависимости. Стрелка от A к B = “A -> B” = “B зависит от A”.
Селекторы графа:
+model— модель и все upstream.model+— модель и все downstream.+model+— модель + upstream + downstream (full lineage).- Несколько селекторов — пересечение / объединение.
Это критический инструмент:
- Хотите понять «откуда приходит fct_orders» ->
+fct_orders-> видите 5 staging-моделей и source. - Хотите понять «что сломается, если изменю stg_jaffle__customers» ->
stg_jaffle__customers+-> видите 10 downstream-моделей и 2 exposure’а. - Onboarding нового member’а: показываете
+main_dashboard_mart+— он за минуту видит весь поток.
Откуда берётся каждая часть UI
| Элемент UI | Источник |
|---|---|
| Имя и путь модели | manifest.json (parsed from project files) |
| Description | manifest.json (из YAML descriptions + doc blocks) |
| Columns + types | catalog.json (queried from warehouse) |
| Column descriptions | manifest.json (из YAML descriptions) |
| Tests | manifest.json (parsed from YAML + tests/) |
| Lineage graph | manifest.json (parsed ref/source dependencies) |
| Compiled SQL | target/compiled/*.sql (from dbt parse) |
| Raw SQL | manifest.json (model body) |
Поэтому: если column не имеет description в YAML — UI покажет колонку без описания (имя, тип из catalog, но пусто справа). Если column есть в YAML, но нет в warehouse (модель ещё не была material-ed) — UI покажет description, но не покажет тип.
Для полного UI нужны и dbt run (чтобы материализовать) + dbt docs generate (чтобы сгенерить catalog).
Типичный workflow
В реальной разработке:
# 1. Изменили модель + добавили описание в YAML
vim models/marts/fct_orders.sql
vim models/marts/_marts__models.yml
# 2. Материализовали модель
dbt run --select fct_orders
# 3. Сгенерили документацию (читает обновлённый manifest + catalog)
dbt docs generate
# 4. Открыли UI и проверили
dbt docs serve
# -> http://localhost:8080 -> найти fct_orders -> проверить description, lineage
В CI:
# В pipeline:
dbt deps # пакеты
dbt build # все модели + тесты
dbt docs generate # документация
# -> push target/ в S3 / GitHub Pages
Документация деплоится автоматически после каждого merge в main. Аналитики всегда видят актуальную версию.
catalog.json — что внутри
catalog.json — это state warehouse. Для каждой модели:
{
"nodes": {
"model.jaffle_shop.fct_orders": {
"metadata": {
"type": "BASE TABLE",
"schema": "marts",
"name": "fct_orders",
"database": "jaffle_shop_db"
},
"columns": {
"order_id": {
"type": "INTEGER",
"index": 1,
"name": "order_id",
"comment": null
},
"amount_usd": {
"type": "DECIMAL(10,2)",
"index": 2,
"name": "amount_usd"
}
},
"stats": {
"row_count": { "value": 50432 },
"bytes": { "value": 1572864 }
}
}
}
}
Откуда:
metadata— изINFORMATION_SCHEMAwarehouse.columns— изSELECT * LIMIT 0или INFORMATION_SCHEMA.stats— warehouse-specific (DuckDB / Postgres имеют свои источники).
Если запустить dbt docs generate без dbt run — модели нет в warehouse, catalog будет пустой для этих моделей. UI покажет descriptions из manifest, но без типов колонок.
dbt docs generate --no-compile — пропускает dbt parse и dbt compile, использует существующий manifest. Быстрее, если только обновляете catalog. Но для production — лучше делайте full generate.
manifest.json — структура проекта
manifest.json — это structure dbt-проекта. Содержит все nodes:
{
"nodes": {
"model.jaffle_shop.fct_orders": {
"name": "fct_orders",
"resource_type": "model",
"package_name": "jaffle_shop",
"path": "marts/core/fct_orders.sql",
"description": "**Grain**: один заказ ...",
"depends_on": {
"nodes": [
"model.jaffle_shop.stg_jaffle__orders",
"model.jaffle_shop.dim_customers"
]
},
"columns": {
"order_id": {
"name": "order_id",
"description": "Primary key",
"data_tests": ["not_null", "unique"]
}
},
"config": {
"materialized": "table",
"schema": "marts",
"tags": ["finance"]
}
}
},
"sources": { ... },
"macros": { ... },
"docs": { ... },
"exposures": { ... },
"metadata": {
"dbt_version": "1.10.2",
"generated_at": "2026-05-19T10:23:45Z",
"project_name": "jaffle_shop"
}
}
Это источник правды для UI. Все descriptions, dependencies, configs, tests — отсюда.
manifest.json также используется для state comparison в CLI (dbt run --state ./prod-manifest --select state:modified).
Хостинг документации
Production-проекты обычно деплоят docs на shared URL:
| Хостинг | Как |
|---|---|
| GitHub Pages | Push target/ в gh-pages branch. Free, простой. |
| Netlify | Подключить repo, build command = dbt docs generate, publish dir = target/. |
| S3 + CloudFront | aws s3 sync target/ s3://bucket/. Кастомный домен. Стандарт для enterprise. |
| dbt Cloud | Если вы на dbt Cloud — есть встроенный hosting через “Documentation tab”. |
| Internal nginx | Скопировать target/ на сервер, отдавать через nginx. |
GitHub Pages — самый простой старт для junior проекта.
Не публикуйте dbt docs открыто в интернет, если в descriptions есть бизнес-чувствительная информация (формулы метрик, размеры таблиц, имена клиентов в descriptions). Используйте authentication (Netlify Identity, CloudFront signed URLs, basic auth nginx).
Что часто ломается
Попробуй сам
В вашем dbt-проекте:
dbt run # материализовать все модели
dbt docs generate # сгенерить документацию
dbt docs serve # запустить локальный сервер
Откройте http://localhost:8080. Поэкспериментируйте:
- Поиск: найдите модель по части имени.
- Открыть модель: посмотрите description, columns, code (raw vs compiled).
- Lineage graph: нажмите кнопку Lineage. Выделите модель в центре. Видите upstream / downstream.
- Селекторы графа: введите
+fct_orders(для примера) — увидите всех предков. - Найти source: откройте source jaffle. Посмотрите freshness section (если настроили
loaded_at_field).
Бонус: запустите dbt run без какой-то модели (dbt run --exclude fct_orders). Запустите dbt docs generate. В UI откройте fct_orders — что показывается? Description есть, но columns без types — потому что таблицы в warehouse нет.
Ключевые выводы
dbt docs generateсобирает manifest.json (структура) и catalog.json (state warehouse).dbt docs serve— простой static HTTP-сервер для target/index.html.- UI состоит из: sidebar (project hierarchy), main area (model details: description, columns, code, tests), lineage graph.
- Lineage graph — самая ценная часть. Селекторы
+model,model+,+model+для навигации. - Descriptions в UI отрисовываются как rendered markdown (из YAML + doc blocks).
- catalog.json пустой для моделей, которые не были
dbt run. UI покажет description, но без типов колонок. - Хостинг production: GitHub Pages / Netlify / S3 + CloudFront / nginx. Документация — статический сайт.
- CI pipeline: после
dbt buildзапускайтеdbt docs generateи пушитеtarget/на хостинг.