The dbt Lineage Graph: A Practical Guide to Reading It Correctly
Itโs easy to open the lineage graph in dbtโs documentation site, admire how connected everything looks, and move on without actually using it for anything. The graph is genuinely useful, but only once you know how to filter it, read direction correctly, and extract a specific answer from it rather than just browsing it as a pretty diagram.
What Youโre Actually Looking At
The lineage graph, accessible through dbt Docs Serve, is a visual rendering of the same DAG covered conceptually in Data Lineage (DAG) โ nodes are sources, models, seeds, and snapshots; edges are ref() and source() calls. Direction matters: an arrow points from an upstream dependency toward the downstream model that consumes it.
raw.orders โโโถ stg_orders โโโถ customer_orders โโโถ sales_summaryReading this left to right: raw.orders feeds stg_orders, which feeds customer_orders, which feeds sales_summary. If youโre standing at customer_orders and looking left, thatโs โupstreamโ โ what this model depends on. Looking right is โdownstreamโ โ what depends on this model.
Filtering to a Manageable View
On any project beyond a handful of models, the full graph is visually overwhelming โ dozens or hundreds of nodes with no way to focus on what matters for the question you actually have. Every lineage view supports filtering to a specific model plus a configurable number of hops in either direction.
- 1 hop upstream/downstream: shows only direct parents and children โ useful for a quick โwhat immediately feeds this, and what immediately consumes it.โ
- Full upstream: every source and model this one ultimately depends on, however many layers deep โ useful before making a breaking change, to see the complete blast radius of what depends on this data.
- Full downstream: the complete set of models (and, where configured, exposures like dashboards) that would be affected by a change here.
Using the Graph for a Real Impact-Analysis Question
Say you need to change a columnโs meaning in stg_orders โ perhaps status needs a new value added. The graph answers, without reading a single line of SQL: which models filter or aggregate on status, and transitively, which dashboards or reports ultimately depend on those models. Click stg_orders, expand full downstream, and every affected model is visible in one view โ the alternative is manually grepping for status across every SQL file and hoping you didnโt miss a reference.
The Graph Includes Exposures, Not Just Models
A detail thatโs easy to miss: if your project documents exposures โ BI dashboards, reports, or other downstream consumers formally declared in YAML (covered in a later guide on dbt Exposures) โ those appear in the lineage graph too, as terminal nodes. This means the graph can genuinely answer โwhich dashboards break if I change this,โ not just โwhich modelsโ โ provided exposures have actually been declared for the dashboards that matter.
Command-Line Equivalent for Scripting
The visual graph is best for exploration; for scripting or CI checks, the same graph traversal is available via dbt ls with graph operators, as covered in dbt run:
# Everything downstream of stg_orders, machine-readabledbt ls --select stg_orders+ --output jsonThis is what a CI job would use to determine, programmatically, which tests need to run for a given pull requestโs changed files โ the visual graph and the command-line selector are two views onto exactly the same underlying dependency data.
Common Misreadings of the Graph
Confusing upstream and downstream direction. Itโs a common mistake under time pressure to trace the wrong direction and conclude a change is safe when it isnโt (or vice versa) โ always confirm which direction youโre looking before drawing a conclusion.
Assuming the graph shows column-level lineage by default. Most setups show model-level lineage (which models depend on which) rather than column-level (which specific output column derives from which specific input column) โ column-level lineage requires additional tooling or a newer dbt/adapter feature set, and isnโt universally available.
Treating an unconnected node as an error. A model with no visible upstream in the graph might genuinely have no dependencies (a seed-only model, or one generating synthetic data) โ not every node needs incoming edges.
Comparing Lineage Before and After a Refactor
When restructuring a section of a project โ splitting one large model into several smaller staging models, for instance โ comparing the lineage graph before and after the change is a quick sanity check that the refactor preserved the intended dependency structure. A model that should now depend on three new staging models, but the graph shows it still pointing at the old single model, indicates the ref() calls werenโt fully updated โ a mistake thatโs easy to make manually and immediately obvious once you look at the actual rendered graph rather than trusting that the refactor was complete.
Common Mistakes
Only using the graph for browsing, never for a specific question. The graphโs real value is answering โwhat breaks if I change thisโ before you change it, not admiring the overall shape of the project.
Not declaring exposures for dashboards that matter. Without them, the lineage graphโs downstream view stops at the last dbt model โ it canโt tell you which actual dashboards are affected, even though thatโs usually the question that matters most to a business stakeholder.
Relying on the graph without corroborating it against actual test coverage. The graph shows dependency structure, not correctness โ a model can be perfectly connected in lineage and still be untested and wrong.
Summary
| Use case | How the lineage graph helps |
|---|---|
| โWhat does this model depend on?โ | Filter to upstream view |
| โWhat breaks if I change this?โ | Filter to downstream view, including exposures |
| Onboarding to an unfamiliar project | Trace backward from a known dashboard/table |
| CI impact analysis | dbt ls --select model+ --output json, the scriptable equivalent |
The lineage graph earns its keep the moment you use it to answer a specific, concrete question โ reserved for actual impact analysis and debugging, itโs one of the most practical tools dbt gives you for working confidently in an unfamiliar or rapidly-changing project.