Datatrail
Blog / Guides 10 min read

How to Visualize dbt Lineage: The DAG, Its Limits, and Column-Level Graphs

Last updated July 2026 · Datatrail

Lineage map
Lineage mapped from query history. Read-only connection.
0

Read-only connection. Datatrail never moves or mutates your data.

The fastest way to visualize dbt lineage is the built-in docs site: run dbt docs generate and dbt docs serve, and dbt draws a directed acyclic graph (the DAG) of your models from the ref() and source() calls in your project. That gives you a free, accurate model-level dependency graph. Its limits are that it stops at your dbt project boundary, so raw tables nobody modeled, ad hoc queries, and the BI dashboards downstream do not appear, and it is model-level rather than column-level. To visualize the full picture, out to the columns and the dashboards, you pair the dbt DAG with a warehouse-native column-level lineage graph.

dbt knows how your models connect because you told it, every time you wrote a ref(). That makes dbt one of the easiest places to get a real lineage picture. Here is how to visualize it, and where the built-in view runs out.

The built-in way: dbt docs and the DAG

dbt ships a lineage visualization out of the box. Two commands get you there:

  • dbt docs generate compiles your project and produces the documentation artifacts, including the dependency graph.
  • dbt docs serve starts a local site where you can browse models and, crucially, open the lineage graph view.

The graph is a DAG, a directed acyclic graph, built from the ref() and source() calls in your models. Every time you write ref('stg_orders') inside fct_orders, you have declared an edge, and dbt assembles all of those edges into the picture. You can click any node to see its upstream parents and downstream children, and use dbt's node selection syntax to focus the view, for example everything downstream of a model with dbt ls --select stg_orders+. For a project that lives entirely in dbt, this is genuinely useful and it costs nothing.

Reading the graph without drowning in it

On a small project the full DAG is legible. Past a hundred models it turns into the hairball everyone eventually screenshots and jokes about. A few habits keep it useful:

  • Select, do not scroll. Use the graph's selector to show one model plus its ancestors and descendants rather than the whole project. The answer to "what depends on this?" is a focused subgraph, not the entire map.
  • Lean on layers. A clean staging, intermediate, and marts structure makes the DAG readable because the left-to-right flow matches your mental model. A tangled graph is often telling you the project structure itself is tangled.
  • Watch for the long tail. Models with a very high downstream count are your critical nodes; a change there has the widest blast radius, and they deserve the most tests.

If your goal is understanding the project so analysts can query it confidently, the dbt DAG plus good documentation goes a long way, and pairing it with a tool that lets people ask questions of the modeled data in plain English means the graph and the querying reinforce each other rather than living in separate tools.

Where the dbt DAG stops

The dbt graph is accurate about one thing: dependencies you expressed with ref() and source(), inside your dbt project. That precision is also its boundary. Three gaps matter.

It ends at the project edge. The DAG shows your models and their declared sources. The raw landing tables that no source points at, the tables another team maintains, the query an analyst runs by hand against your marts: none of that is in the graph, because dbt only knows what your project declares. If a break comes from outside the project, the dbt DAG will not show you the path.

It is model-level, not column-level. The dbt DAG tells you fct_orders depends on stg_orders. It does not, on its own, tell you that fct_orders.net_revenue is derived from stg_orders.amount minus stg_refunds.amount. For impact analysis, column-level is the resolution that matters, because most changes touch a column, not a whole table. dbt has some column-level lineage in its paid Explorer tier, but the free docs DAG is model-level.

It does not reach the dashboards. The DAG ends at your marts. The Looker explore, the Tableau workbook, and the reverse-ETL sync that read those marts are downstream of dbt, so the graph stops one hop short of where a broken column is actually noticed, on someone's dashboard.

Visualizing the full picture: column-level, past the project edge

To see lineage that starts before your dbt project and ends at the dashboard, and resolves to the column, you read it from the warehouse rather than from the project files. A warehouse-native tool connects read-only, parses the query history the warehouse already records, and reconciles it against your dbt graph. Because it reads the SQL that actually ran, it captures the un-modeled tables and ad hoc queries dbt never sees, resolves lineage to individual columns, and follows each column out into the BI layer.

That is what Datatrail's lineage diagram renders: the same left-to-right flow as the dbt DAG, but at column-level resolution and extended past the project boundary to the dashboards. From there, impact analysis lists every downstream model and dashboard that reads a column before you change it, which is the question a lineage picture is usually there to answer. If you want the mechanics of the dbt graph specifically, our guide to the dbt dependency graph goes deeper, and dbt lineage in Datatrail shows how the project graph and the warehouse graph line up.

The short version

For a quick, free, accurate view of your model dependencies, use dbt docs generate and dbt docs serve and read the DAG, focusing it with node selection rather than trying to take in the whole hairball. When you need column-level detail, the tables outside your project, or the path all the way to the dashboard, pair the dbt DAG with a warehouse-native column-level graph. You can see that graph on your own warehouse in a few minutes from the product.

See how your data flows, end to end

Connect your warehouse read-only and map lineage, freshness, and downstream impact before a change breaks a dashboard. Transparent pricing, no card to start.