Data Engineering  /  dbt

๐Ÿ”„ dbt โ€” Data Build Tool 60 guides ยท updated 2026

Analytics engineering with SQL โ€” models, tests, sources, and Jinja macros that turn raw warehouse tables into trustworthy, documented data products.

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.

models/marts/_exposures.yml
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: dashboard

The 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: high

maturity: 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:

Terminal window
dbt ls --select sales_summary+ --resource-type exposure
exposure.my_project.executive_revenue_dashboard

This 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')
Terminal window
# Every critical-tagged exposure, to review before a major upstream migration
dbt ls --select tag:critical --resource-type exposure

This 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

FieldPurpose
depends_onWhich dbt models this exposure consumes
typeCategorizes the consumer (dashboard, ML model, notebook, application)
maturitySignals how production-critical this consumer is
ownerWho 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.