Dataobservability
Blog / How to 8 min read

Column Level Lineage in dbt: How to Get It, What It Misses

August 2026 · Dataobservability

SNOWFLAKE · PROD
247 tables |
Break a monitor:

Alerted #data-eng 0.8s ago.

Downstream impact · consumers at risk

INCIDENT #1042 OPEN · owner @you

Live console · pick a break, watch it get caught

dbt does have column level lineage, but it is narrower than most teams expect. It lives in dbt Catalog (the feature that used to be called dbt Explorer), it is available on Enterprise and Enterprise+ plans only, and it covers models, sources, and snapshots. The limitation that catches people out is documented but rarely read: dbt column level lineage reflects the lineage from select statements in your models, and does not reflect other usage such as joins and filters. If you are on dbt Core, there is no built-in column level lineage at all.

Does dbt have column level lineage?

Yes. Column level lineage is part of dbt Catalog, which dbt Labs renamed from dbt Explorer. You reach it by opening a model, source, or snapshot, going to the Columns tab, and expanding a column card, which shows where that specific field came from and what it feeds. There is no extra setup if your account is on a plan that includes Catalog, and dbt refreshes the lineage after each run executed in a production or staging environment.

The important qualifier is the plan. Column level lineage is available to dbt Enterprise plans that can use Catalog, which in practice means Enterprise and Enterprise+. Developer and Team plans get the model level DAG, which is table level lineage: it tells you that stg_orders feeds fct_revenue, but not which field inside stg_orders produced which field inside fct_revenue.

Which dbt plan do you need for column level lineage?

What you want to tracedbt Coredbt Developer / Teamdbt Enterprise / Enterprise+
Model to model DAG (table level)Yes, via the docs siteYesYes
Column to column lineageNoNoYes, in dbt Catalog
Lineage outside the dbt projectNoNoNo
Lineage refreshed after each prod runManual rebuildYesYes

That third row is the one worth pausing on, and it applies to every dbt tier equally. dbt only knows about what dbt does. A column loaded into the warehouse by an ingestion tool, written by a notebook, produced by a stored procedure, or computed inside your BI layer is outside the project, so it is outside the graph. For most teams the ingestion half of the stack sits with a separate data integration platform connecting apps, APIs, and databases, and nothing dbt produces will trace a field back through that hop.

What dbt column level lineage does not capture

This is the section worth reading before you rely on the graph during an incident. dbt documents its own limits clearly, and they are more consequential than the feature list suggests.

Only select statements, not joins or filters. The lineage reflects columns as they appear in select clauses. If a column is used in a join condition or a where clause but never selected, that relationship does not appear. This matters more than it sounds: a field that silently filters your revenue model is exactly the kind of dependency you want to know about before someone changes it, and it is precisely the kind dbt will not show you.

Parsing failures on real world SQL. Column level lineage relies on SQL parsing, so it breaks where parsing breaks. dbt names the cases: complex or ambiguous SQL produces a parsing error, Python models cannot be parsed at all, and a column's origin can be unknown with JSON unpacking or lateral joins. A model that hardcodes a table name instead of using ref also produces an unknown error, which is a good argument for treating ref discipline as a lineage requirement rather than a style preference.

Nothing before the source, nothing after the model. dbt sources are the upstream boundary and dbt models are the downstream one. If your finance dashboard reads a mart, the lineage stops at the mart. That gap is where most incident time actually goes, because the question people ask under pressure is which dashboard broke, not which model.

How to get column level lineage with dbt Core

dbt Core does not ship column level lineage, so the options are to derive it yourself or to get it from a layer that sits underneath dbt. Three approaches work in practice.

Parse the compiled SQL yourself. Every dbt run produces manifest.json and compiled SQL for each model. A SQL parser can turn those into column edges. This is real engineering work, it needs maintenance as your SQL gets more exotic, and you will hit the same lateral join and JSON unpacking problems dbt hits, because they are properties of SQL parsing rather than of dbt.

Use an open source metadata platform. DataHub and OpenMetadata both ingest dbt artifacts and produce column level lineage where the connector supports it, and OpenLineage has a dbt integration that emits runtime events. All are Apache 2.0 and genuinely capable. The cost moves rather than disappears: you operate a metadata service, a search index, a database, and the ingestion jobs, and connector breakage becomes your on-call.

Take lineage from the warehouse instead. Snowflake, Databricks, and BigQuery all expose some column level lineage natively, because they see every statement that ran regardless of what issued it. That is a different and often better vantage point than dbt's, and it is covered in more detail on our column level data lineage page along with the specific limits each platform documents.

dbt column lineage vs warehouse column lineage

These two are complementary rather than competing, and understanding why makes the buying decision much easier. dbt knows intent. It knows that a model is called fct_revenue, that it is owned by the analytics team, that it has tests attached, and how the DAG is meant to be shaped. What it does not know is anything that happened outside the project.

The warehouse knows reality. Query history records every statement that touched the data, including the ingestion job, the notebook, the reverse ETL sync, and the CREATE TABLE AS somebody ran once in March that a dashboard now quietly depends on. What it lacks is intent: it does not know which of those tables was supposed to exist.

Parsing both gives you the modeled intent and the executed reality in one graph, which is how you end up with lineage that survives contact with production. That combination is what our dbt data observability integration is built on, and it is why the column graph includes the pipelines nobody documented rather than only the ones somebody modeled.

How to check your dbt column lineage is actually complete

Do this before you trust the graph in an incident, not during one. It takes about fifteen minutes.

Pick four awkward columns rather than four easy ones. Choose a field produced by a join across three tables, a field that comes out of a Python model or a UDF, a field that is used in a where clause but never selected, and a field in a table that was created by hand and never documented. Trace each one upstream to source and downstream to its final consumer.

What you are looking for is not whether the tool works. It is where the graph goes quiet, because every implementation goes quiet somewhere. Write down the gaps you find and treat them as known blind spots rather than discovering them at 2am. If three of your four test columns trace cleanly and the fourth stops at a Python model, that is a perfectly workable graph as long as the team knows that is where it stops.

Frequently asked questions

Is column level lineage available in dbt Cloud on all plans?
No. Column level lineage is available to dbt Enterprise plans that can use Catalog, meaning Enterprise and Enterprise+. Developer and Team plans get the model level DAG, which is table level lineage. There is no additional setup needed once you are on a qualifying plan, and the lineage refreshes after each run executed in a production or staging environment.

What happened to dbt Explorer?
It was renamed. The feature that was called dbt Explorer is now dbt Catalog, and column level lineage lives inside it. You find it by opening a model, source, or snapshot, selecting the Columns tab, and expanding an individual column card. Older documentation and blog posts still refer to Explorer, so both names describe the same thing.

Why is a column missing from my dbt lineage?
Usually one of four reasons dbt documents. The column is used in a join or filter but never selected, so it falls outside what the lineage reflects. The model is written in Python, which cannot be parsed. The SQL involves JSON unpacking or a lateral join, so the origin cannot be resolved. Or the model hardcodes a table name instead of using ref, which produces an unknown origin.

Does dbt column level lineage include my BI dashboards?
No. dbt lineage stops at the boundary of the dbt project, so sources are the upstream limit and models are the downstream one. Fields consumed by Looker, Tableau, or Power BI are not in the graph, which means the question most incidents actually turn on, which dashboard just broke, is not one dbt lineage can answer by itself.

Can I get column level lineage without upgrading to dbt Enterprise?
Yes, by getting it from a different layer. Open source metadata platforms such as DataHub and OpenMetadata ingest dbt artifacts and build column lineage, and warehouse native lineage in Snowflake, Databricks, and BigQuery traces columns from query history regardless of dbt plan. An observability platform that parses both warehouse history and dbt metadata gives you the combined graph without a dbt tier change.

Does column level lineage slow down dbt runs?
No. The lineage is derived from metadata and compiled SQL after a run rather than computed during one, so it does not add to model execution time. Warehouse based approaches read query history, which is metadata the warehouse already writes, so they do not scan your tables or add meaningful compute either.

Where this leaves you

If you are on dbt Enterprise, you already have column level lineage inside the project, and the useful next step is knowing its two real boundaries: select statements only, and nothing outside dbt. If you are on Core or Team, dbt is not going to give you column lineage at all, and upgrading a whole dbt plan to get one feature is an expensive route to it.

Either way, the gap that matters most is the same one: the graph needs to reach past the dbt project into the warehouse underneath and the dashboards on top, and it needs to be connected to alerting so a schema change on a source column tells you which downstream fields it breaks and who owns them. Lineage you browse is documentation. Lineage that fires is infrastructure. If you want the fuller picture of how the platforms differ, the column level lineage comparison lays out what each one captures and exactly where each one stops, and automated data lineage covers how the graph is built in the first place.

Catch broken data before your stakeholders do

Connect your warehouse and get all five pillars monitoring from one read-only connection. Transparent pricing, no credit card.