Docs & Code Guide

A living diagram from dbt: manifest.json already holds the lineage, regenerate the view after every dbt build

Nobody should draw dbt lineage by hand, because dbt computes it on every run. Each command that compiles the project writes target/manifest.json, and inside it parent_map and child_map spell out every edge in the DAG. A living lineage diagram is therefore a rendering problem, not a discovery problem: read the manifest, draw the curated view, and re-run that step after every dbt build.

8 min readFor analytics engineers who own the dbt project and its wiki page

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

221/20003 credits left
Try:

No account needed · Editable canvas, not a picture

manifest.json: the lineage, already computed

Every dbt command that parses the project, build, run, compile, writes target/manifest.json. Its nodes object keys every model, seed, snapshot, and test by a unique_id like model.analytics.stg_orders, and two companion maps give the graph without any SQL parsing on your side: parent_map lists what each node depends on, child_map lists what depends on it. The lineage your diagram needs is those two maps, verbatim.

This is what an MCP-connected agent reads to draw or update the diagram: no ref() spelunking, no dbt-specific parsing, one JSON file that is always exactly as fresh as the last build.

dbt build

# Everything downstream of one staging model
jq '.child_map["model.analytics.stg_orders"]' target/manifest.json

# Declared downstream consumers
jq '.exposures | keys' target/manifest.json

catalog.json and exposures fill in what the manifest cannot

The manifest knows the graph but not the warehouse. dbt docs generate queries the warehouse and writes target/catalog.json with the actual columns, types, and row counts per relation, which is the artifact to use when the diagram should show key columns on the marts. Worth knowing before you promise it to anyone: dbt's artifacts give model-level lineage, not column-level edges; catalog.json lists columns but does not trace them across models.

Exposures close the graph on the far side. An exposure is a YAML declaration that a dashboard, an ML job, or an application consumes specific models, and it lands in the manifest like any node. Declaring them is what turns the diagram's edge into an answer for the question that actually hurts: what breaks downstream if this model changes.

dbt docs already draws a DAG, so why another view

Fair question, and dbt docs deserves the credit: its lineage graph is interactive, complete, and free with the project. It is also unfiltered by design, every node at equal weight, which is the wrong altitude for a wiki page where a product manager or a new hire needs sources, layers, marts, and consumers at a glance. The curated diagram exists for that reader: staging, intermediate, and mart zones, the dozen models that matter, exposures drawn as real boxes.

Scope note to keep the pages straight: this guide covers the lineage diagram. Keeping the dbt docs site itself fresh, hosting and CI for dbt docs generate, is a different workflow, covered in keep dbt docs in sync. And the dbt lineage diagram generator owns the first-time generation, from a pasted manifest excerpt or a description.

One CI step after dbt build

The loop mirrors every other source in this series, with an unusually convenient artifact. CI already runs dbt build on merge; the fresh manifest is sitting in target/ when it finishes. Add one step: an agent connected to Datadef's MCP server (registry io.datadef/mcp) reads the manifest, diffs it against the diagram, and applies the changes, new models into their layer zones, deleted ones removed, exposure edges updated. The connection needs an API key, available on paid plans.

Datadef does not watch the repo or your warehouse; nothing regenerates by itself. But since the manifest regenerates on every build anyway, the marginal cost of the diagram step is one command, and the wiki embed does the rest: an updated diagram shows up in the Notion or Confluence page embedding it within minutes.

What manifest.json leaves out

Model-level lineage is what the artifacts give; column-level lineage is not in the manifest, and a diagram claiming it would be decorating guesses. The embed requires the Datadef project to be shared public, which for lineage diagrams naming internal tables deserves an explicit decision rather than a default. And exposures only appear if the team declares them: an undeclared dashboard is invisible to dbt and therefore to the diagram, which is an argument for declaring exposures, not against the diagram.

The manifest is always fresh

Every dbt build rewrites target/manifest.json. A diagram step that reads it in the same CI job can never work from stale lineage.

FAQ

How do I automate a dbt lineage diagram?

Read target/manifest.json, which every dbt build rewrites: parent_map and child_map hold the full node graph. Have an MCP-connected agent draw the curated view from it once, then add one CI step after dbt build that has the agent update the diagram from the fresh manifest. Pages embedding the diagram refresh within minutes of an update.

Where does dbt store lineage information?

In target/manifest.json, written by every command that parses the project. The nodes object keys every model by unique_id, and parent_map plus child_map list every dependency edge in both directions, so lineage extraction needs no SQL parsing at all.

Is column-level lineage in manifest.json?

No. dbt artifacts carry model-level lineage. catalog.json, written by dbt docs generate, lists the actual columns and types per relation from the warehouse, but it does not trace columns across models. A diagram from dbt artifacts can show key columns on nodes, not column-to-column edges.

What are dbt exposures and why draw them?

Exposures are YAML declarations that something downstream, a dashboard, an ML job, an application, consumes specific models. They land in the manifest as nodes, so the diagram can draw the edges leaving dbt. That answers the question lineage exists for: what breaks downstream if this model changes.

Does the lineage diagram update when models change?

After one CI command, yes. Nothing watches the repository, but since CI already runs dbt build on merge, a step that has an agent read the fresh manifest and update the diagram closes the loop. The wiki embed then refreshes on its own within minutes.

Is the dbt docs lineage graph enough?

For engineers exploring the project, often yes, and it is free with dbt. It shows every node at equal weight though, which is the wrong altitude for a wiki overview. A curated diagram with layer zones and declared exposures serves the reader who needs the shape of the platform in ten seconds.