dbt Documentation Guide
Documentation transforms dbt projects from mystery code into trusted data products. This guide covers creating and maintaining excellent documentation.
Why documentation matters
Trust and transparency
Stakeholders trust data they understand. Documentation explains:
- Where data comes from
- How it's transformed
- What it represents
- Who owns it
Onboarding acceleration
New team members become productive faster when they can:
- Explore the data catalog
- Understand model purposes
- Find relevant datasets
- Learn from existing patterns
Error reduction
Clear documentation prevents:
- Misinterpreted metrics
- Incorrect joins
- Wrong assumptions about data quality
Documentation types
Model descriptions
Every model needs a description explaining:
Required elements:
- Purpose: What business question does this answer?
- Grain: One row per what?
- Data sources: Where does the data come from?
- Owner: Who maintains this model?
- Update frequency: How often does it refresh?
Example:
version: 2
models:
- name: fct_orders
description: >
## Overview
Fact table containing all orders placed on the platform.
## Grain
One row per order.
## Business Logic
- Includes all completed, pending, and cancelled orders
- Excludes test orders and internal transactions
- Amounts are in USD
- Taxes calculated at time of order
## Data Sources
- Raw orders: Shopify API
- Customer data: CRM system
## Owner
Finance team (finance@company.com)
## Update Frequency
Hourly, refreshed at :05 past the hour
## Known Issues
- Orders from 2019 may have missing customer IDs due to data migration
columns:
- name: order_id
description: Primary key. Unique identifier for each order.
Column descriptions
Document every column that users might query:
columns:
- name: order_id
description: >
Unique identifier for each order.
Generated by Shopify and immutable.
- name: order_amount
description: >
Total order value in USD, including taxes and shipping.
Use net_amount for revenue calculations (excludes taxes).
- name: customer_segment
description: >
Customer classification based on lifetime value.
- enterprise: LTV > $100K
- mid_market: LTV $10K-$100K
- smb: LTV < $10K
Source documentation
Document external data sources:
version: 2
sources:
- name: shopify
description: >
E-commerce platform data ingested via Shopify API.
Updated hourly via Fivetran sync.
tables:
- name: orders
description: >
Orders placed on the Shopify store.
Includes both B2C and B2B transactions.
columns:
- name: id
description: Shopify's unique order identifier
Macro documentation
Document reusable macros:
{#
Cents to dollars conversion macro.
Args:
column_name: The column containing cents value
precision: Number of decimal places (default: 2)
Returns:
SQL expression converting cents to dollars
Example:
{{ cents_to_dollars('order_amount_cents') }}
-> order_amount_cents / 100.0
#}
{% macro cents_to_dollars(column_name, precision=2) %}
({{ column_name }} / 100.0)::numeric(16, {{ precision }})
{% endmacro %}
Writing effective descriptions
Be specific
Vague:
description: This table contains orders
Specific:
description: >
Fact table of customer orders placed through web and mobile channels.
Includes completed, pending, and cancelled orders from 2020-present.
Include business context
Explain the "why" not just the "what":
description: >
Customer lifetime value (CLV) calculated using the predictive model
from data science team. Used for customer segmentation and
marketing campaign targeting. Updated weekly on Mondays.
Document caveats
Be honest about limitations:
description: >
## Important Notes
- Excludes orders with status 'test'
- Refunds not yet deducted (see fct_refunds)
- Currency conversion uses end-of-day rates
- ~5% of 2019 orders missing customer_id due to data migration
Use consistent terminology
Standardize terms across your project:
| Term | Meaning |
|---|---|
| Revenue | Net sales amount (excluding taxes) |
| Orders | Completed transactions only |
| Customer | Unique individual or company |
| Active | Had activity in last 90 days |
Documentation structure
Organizing schema.yml files
Option 1: One file per directory
models/
├── staging/
│ ├─ ─ _staging__sources.yml # All sources
│ ├── _staging__models.yml # All staging models
│ └── ...
└── marts/
├── _marts__models.yml # All mart models
└── ...
Option 2: One file per model
models/
├── staging/
│ ├── stg_customers.sql
│ ├── stg_customers.yml # Model-specific docs
│ └── ...
Recommended: Use directory-level files for related models to keep documentation organized but not fragmented.
Documentation hierarchy
version: 2
models:
# Group related models
- name: fct_orders
# Model-level description
description: Orders fact table
# Model config
config:
materialized: table
# Column documentation
columns:
- name: order_id
description: Primary key
tests:
- unique
- not_null
Advanced documentation
Adding owners
Assign ownership for accountability:
models:
- name: fct_orders
meta:
owner: "@finance-team"
contact: "finance@company.com"
Version control
Track documentation changes:
models:
- name: fct_orders
meta:
version: "2.1.0"
last_updated: "2024-01-15"
changelog: "Added tax_amount column"
Data dictionary
Create a comprehensive data dictionary:
# models/_data_dictionary.yml
version: 2
models:
- name: dim_customers
description: "{{ doc('customer_dimension') }}"
Create models/docs.md:
{% docs customer_dimension %}
# Customer Dimension
Comprehensive customer information including demographics,
preferences, and lifetime metrics.
## Key Metrics
- **Lifetime Value (LTV):** Predicted total revenue
- **Acquisition Channel:** How customer was acquired
- **Segment:** Customer classification (enterprise, mid_market, smb)
## Data Quality
- 99.5% of customers have valid email addresses
- 95% of customers have complete demographic data
- Updated daily with ~2 hour lag
{% enddocs %}
Documentation maintenance
Code review checklist
Ensure documentation quality:
- All models have descriptions
- All columns have descriptions
- Business logic is explained
- Grain is documented
- Owners are assigned
- Caveats are noted
Automation
Check documentation coverage:
# .github/workflows/docs-check.yml
name: Documentation Check
on: [pull_request]
jobs:
check-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check documentation
run: |
python scripts/check_docs_coverage.py
Create scripts/check_docs_coverage.py:
import yaml
import sys
from pathlib import Path
def check_coverage():
models_without_docs = []
columns_without_docs = []
for yml_file in Path('models').rglob('*.yml'):
with open(yml_file) as f:
content = yaml.safe_load(f)
if 'models' in content:
for model in content['models']:
if not model.get('description'):
models_without_docs.append(model['name'])
for col in model.get('columns', []):
if not col.get('description'):
columns_without_docs.append(f"{model['name']}.{col['name']}")
if models_without_docs or columns_without_docs:
print("Missing documentation:")
for m in models_without_docs:
print(f" Model: {m}")
for c in columns_without_docs:
print(f" Column: {c}")
sys.exit(1)
else:
print("✓ All models and columns documented")
if __name__ == '__main__':
check_coverage()
Regular reviews
Schedule quarterly documentation audits:
- Identify undocumented models
- Update stale descriptions
- Review and refresh data dictionaries
- Gather stakeholder feedback
- Update terminology standards
Documentation in dbt-Workbench
Viewing documentation
The dbt-Workbench docs viewer provides:
- Interactive model documentation
- Column-level details
- Lineage integration
- Test results
- Owner information
Searching documentation
Use the catalog to search:
- Model names
- Column names
- Descriptions
- Tags
Embedding documentation
Share documentation links:
https://dbt-workbench.company.com/docs/marts/fct_orders
Documentation templates
Model template
version: 2
models:
- name: [model_name]
description: >
## Overview
[What does this model do?]
## Grain
One row per [entity/event].
## Data Sources
- [Source 1]
- [Source 2]
## Business Logic
[Key transformations and logic]
## Owner
[Team name] ([contact email])
## Update Frequency
[How often updated]
meta:
owner: "@[team-name]"
columns:
- name: [column_name]
description: [Clear description]
Source template
version: 2
sources:
- name: [source_name]
description: >
[What is this source?]
## Ingestion
- Method: [API/ETL/manual]
- Frequency: [How often updated]
- System: [Source system name]
tables:
- name: [table_name]
description: [Table description]
FAQ
What should I document in dbt?
Document all models, columns, sources, and snapshots. Include descriptions, business context, owners, and any assumptions or caveats about the data.
How detailed should model descriptions be?
Include the grain of the model, what business questions it answers, data sources, transformation logic overview, and any known limitations or caveats.
Can I document macros and tests?
Yes. Document macros with usage examples and parameter descriptions. Tests are self-documenting through their names, but complex custom tests should include descriptions.
How do I maintain documentation over time?
Make documentation updates part of your PR checklist, schedule quarterly documentation reviews, and use automation to check documentation coverage.