dbt Exposures: Documenting BI Dashboards in Your Lineage Graph
The lineage graph covered in Lineage Graph tells you exactly which models depend on which โ right up until the data leaves dbtโs world and lands in a BI tool. From there, dbt has no visibility by default: it doesnโt know that sales_summary feeds the executive revenue dashboard, or that three different Looker reports all depend on customer_orders. Exposures close this gap by letting you explicitly declare downstream consumers as part of the project.
Declaring an Exposure
An exposure is a YAML declaration, similar in spirit to a source declaration but pointing outward instead of inward.
exposures: - name: executive_revenue_dashboard label: "Executive Revenue Dashboard" type: dashboard maturity: high url: "https://looker.internal/dashboards/executive-revenue" description: "Monthly revenue breakdown by region, reviewed weekly by leadership." depends_on: - ref('sales_summary') - ref('customer_orders') owner: name: "Analytics Team" email: "analytics@company.com"Once declared, sales_summary and customer_orders now show this dashboard as a downstream node in the lineage graph โ dbtโs dependency awareness extends one step past the warehouse, into an actual business artifact people rely on.
Why This Matters for Impact Analysis
Without exposures, โwhat breaks if I change this modelโ stops at the last dbt model in the chain โ you can see that sales_summary feeds nothing else in dbt, but you have no formal record that it also feeds a dashboard leadership checks every Monday. With the exposure declared, that same impact-analysis question (covered generally in Lineage Graph) now correctly surfaces the dashboard as something that would be affected.
Exposure Types
exposures: - name: weekly_ops_report type: application - name: fraud_ml_model type: ml - name: finance_notebook type: notebook - name: executive_dashboard type: dashboardThe type field is primarily descriptive โ it shows up as an icon/category in the documentation site, helping distinguish โa dashboard someone looks atโ from โa downstream ML model consuming this table as a featureโ from โa data science notebook,โ each with a different practical blast radius if something changes.
Maturity: Signaling How Much a Consumer Depends on Stability
exposures: - name: exploratory_finance_notebook type: notebook maturity: low - name: sec_filing_report type: dashboard maturity: highmaturity: high signals this consumer is production-critical and stable โ changes upstream should be reviewed carefully. maturity: low signals an exploratory, less formal consumer where more flexibility exists. This is a documentation convention, not an enforced rule, but itโs a useful signal for anyone deciding how carefully to review a change to an upstream model.
Owner Information for Accountability
owner: name: "Finance Analytics" email: "finance-analytics@company.com"When an upstream model change is about to affect a dashboard, the exposureโs owner field tells you exactly who to loop in before making the change โ rather than discovering after the fact, when the dashboard breaks, that a completely different team than expected was actually relying on it.
A Practical Workflow: Checking Exposures Before a Breaking Change
Before making a schema change to a model with downstream exposures, checking whatโs declared against it is a quick, high-value habit:
dbt ls --select sales_summary+ --resource-type exposureexposure.my_project.executive_revenue_dashboardThis immediately tells you: this specific dashboard, owned by this specific team, needs to be considered (and probably notified) before you ship a breaking change to sales_summary.
Exposures and the Documentation Site
Every declared exposure appears in the generated documentation site (covered in dbt Docs Generate and dbt Docs Serve) as a distinct node type, complete with its URL, owner, and description โ turning what would otherwise be tribal knowledge (โoh yeah, I think marketing uses that table for somethingโ) into something documented, searchable, and visible in the same place as everything else about the project.
Keeping Exposures From Going Stale
Exposures share the same risk as any manually maintained documentation โ if a dashboard is retired or its underlying query changes to use different models, the exposure declaration needs to be updated or removed, or it starts pointing at a stale, misleading dependency. Thereโs no automatic mechanism enforcing this; it depends on the same team discipline that keeps model descriptions accurate.
Tags Combined With Exposures
Since exposures are just another node type in the same project, they can carry tags too, letting you group dashboards the same way youโd group models โ by team, by criticality, by review cadence.
exposures: - name: executive_revenue_dashboard tags: ['critical', 'team_finance'] depends_on: - ref('sales_summary')# Every critical-tagged exposure, to review before a major upstream migrationdbt ls --select tag:critical --resource-type exposureThis combination โ tags for grouping, exposures for declaring real downstream consumers โ is what lets a large project answer โwhich of our most important dashboards would be affected by this changeโ as a single, precise query instead of relying on someoneโs memory of which reports matter most.
Common Mistakes
Not declaring exposures for the dashboards that actually matter most. The lineage graphโs usefulness for real business-impact analysis depends entirely on exposures being declared โ skipping this for high-stakes dashboards defeats much of the point.
Letting exposure declarations drift out of sync with reality. A dashboard that no longer uses a particular model, but still has a stale depends_on entry, misleads anyone checking impact analysis against it.
Treating exposures as purely decorative documentation. Their real value is operational โ checking them before making a change, and notifying the declared owner, not just having them exist as metadata nobody consults.
Summary
| Field | Purpose |
|---|---|
depends_on | Which dbt models this exposure consumes |
type | Categorizes the consumer (dashboard, ML model, notebook, application) |
maturity | Signals how production-critical this consumer is |
owner | Who to notify before a breaking upstream change |
Exposures extend dbtโs lineage awareness one crucial step further โ from โwhich models depend on whichโ to โwhich actual business decisions depend on this data,โ which is ultimately the question that matters most when deciding how carefully to handle a change.