dbt docs generate: Producing Your Projectโs Documentation Automatically
Documentation that lives in a separate wiki, disconnected from the actual code, goes stale within weeks โ someone renames a column, forgets to update the doc, and now the documentation is actively misleading rather than just incomplete. dbtโs approach avoids this by generating documentation directly from the project itself: descriptions you write in YAML, combined with metadata dbt already tracks about every model, source, and column.
Running dbt docs generate
dbt docs generateThis produces two key JSON artifacts inside target/:
manifest.jsonโ a complete representation of your projectโs structure: every model, source, seed, snapshot, macro, test, their configurations, and their dependency relationships.catalog.jsonโ actual warehouse metadata about the tables and views dbt built: column names, data types, row counts where available.
Together, these two files are what powers the interactive documentation site, covered operationally in dbt Docs Serve.
Where Documentation Content Actually Comes From
dbt doesnโt invent descriptions โ every piece of documentation text comes from what youโve explicitly written in YAML files, attached to models, columns, and sources.
models: - name: stg_orders description: "Cleaned, one-row-per-order staging model. Filters out internal test orders." columns: - name: order_id description: "Primary key, unique per order." - name: status description: "Order lifecycle status: pending, shipped, delivered, cancelled, or returned."Running dbt docs generate after adding these descriptions pulls them directly into the generated site โ thereโs no separate documentation-writing step beyond what youโve already declared for testing and organizational purposes.
Documentation Blocks for Longer, Reusable Descriptions
For descriptions that are long, or reused across multiple models (a shared column meaning across several tables), a {% docs %} block keeps YAML files from becoming unwieldy.
{% docs order_status_description %}Order lifecycle status. Possible values:- `pending`: order placed, payment not yet confirmed- `shipped`: payment confirmed, package has left the warehouse- `delivered`: confirmed received by customer- `cancelled`: order cancelled before shipment- `returned`: customer-initiated return, refund processed{% enddocs %}columns: - name: status description: "{{ doc('order_status_description') }}"This is worth doing whenever the same column meaning repeats across multiple models โ a single doc block reused via {{ doc(...) }} stays consistent everywhere itโs referenced, rather than five slightly-drifting copies of similar but not identical text.
What Gets Captured Automatically vs. What You Have to Write
| Captured automatically from project structure | Requires explicit description |
|---|---|
| Dependency graph (which models reference which) | What a model or column actually means |
| Materialization type (table, view, incremental) | Business context and caveats |
Column names and types (from catalog.json) | Why a filter or transformation exists |
| Test coverage per column | Known limitations or edge cases |
This split matters โ dbt gives you the structural skeleton of documentation for free, but the actual, valuable context still requires someone to write it. A project with zero YAML descriptions still generates a lineage graph, but itโs a graph of undocumented boxes.
Generating Docs as Part of a Scheduled Job
Since documentation is derived from the current state of the project, it needs to be regenerated after every meaningful change to stay accurate โ most teams run it as the final step of a production build.
dbt builddbt docs generateRunning dbt docs generate without a preceding successful build still works, but catalog.json will only reflect whatever tables actually exist in the warehouse from the last successful build โ stale documentation isnโt usually catastrophic here, but itโs worth understanding that this command reflects the warehouseโs actual current state, not necessarily your latest uncommitted local changes.
Hosting the Generated Site
dbt docs generate only produces the artifacts โ actually viewing them requires either dbt docs serve locally (covered next) or hosting the generated target/ directoryโs static files somewhere accessible to your team, which is how dbt Cloudโs hosted documentation feature and most self-hosted setups work in practice.
# Typical CI step: generate docs, then upload target/ to a static hostdbt docs generateaws s3 sync target/ s3://internal-docs-bucket/dbt-docs/ --deleteGenerating Docs Without a Live Warehouse Connection
catalog.json requires querying the warehouse for actual column metadata, but manifest.json โ the structural, dependency-graph portion of the documentation โ can be produced without any live connection at all, using --no-compile or by simply running dbt parse instead of a full dbt docs generate.
dbt parseThis is useful in constrained environments (a laptop without VPN access to the warehouse, for instance) where you still want to browse the projectโs structure and lineage graph locally, accepting that column type and row-count information wonโt be available until a full dbt docs generate runs against a live connection.
Common Mistakes
Never adding YAML descriptions and expecting useful documentation anyway. The generated site will show structure and lineage regardless, but without descriptions, itโs a map with no labels โ technically complete, not actually useful to a new team member.
Regenerating docs infrequently. Stale documentation that shows a lineage graph from three model changes ago is actively worse than no documentation, since it looks authoritative while being wrong.
Writing the same column description five times instead of using {% docs %} blocks. This is the exact copy-paste problem macros solve for logic โ documentation benefits from the same reuse discipline.
Summary
| Artifact | Contains |
|---|---|
manifest.json | Full project structure, dependencies, configuration |
catalog.json | Actual warehouse metadata โ columns, types, from built tables |
YAML description: fields | Where all documentation text originates |
{% docs %} blocks | Reusable, longer-form descriptions referenced via doc() |
dbt docs generate turns documentation from a separate, drifting artifact into a byproduct of the project itself โ accurate exactly to the degree that the underlying YAML descriptions are actually kept up to date.