Skip to main content

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:

TermMeaning
RevenueNet sales amount (excluding taxes)
OrdersCompleted transactions only
CustomerUnique individual or company
ActiveHad 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:

  1. Identify undocumented models
  2. Update stale descriptions
  3. Review and refresh data dictionaries
  4. Gather stakeholder feedback
  5. 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.