dbt Exposures
Exposures are YAML declarations that tell dbt about the downstream consumers of your data — dashboards, reports, ML models, applications, and reverse ETL jobs. Defining exposures lets your team see in the lineage graph exactly what depends on each model, who owns each consumer, and what breaks when a model changes.
Why Exposures Exist
Without exposures: dbt lineage graph ends at your mart models. Nobody knows which Tableau dashboard uses fct_orders. You refactor fct_orders, rename a column. Three dashboards break. You find out when the VP complains. With exposures: The lineage graph shows: fct_orders → Revenue Dashboard (owned by Finance) Before you rename a column, you see which dashboards are affected. You notify the Finance team and update the dashboard together.
Defining an Exposure
Create a YAML file (often named exposures.yml) in your models/ folder:
# models/exposures.yml
version: 2
exposures:
- name: revenue_dashboard
label: "Revenue Dashboard"
type: dashboard
maturity: high
url: https://tableau.company.com/views/RevenueDashboard
description: >
The main revenue dashboard used by the Finance and Sales teams.
Updated daily at 7 AM. Used in the Monday morning executive meeting.
depends_on:
- ref('fct_orders')
- ref('dim_customers')
- ref('fct_revenue_monthly')
owner:
name: Finance Data Team
email: finance-data@company.com
Exposure Types
Type Used For --------- -------- dashboard Tableau, Looker, Power BI, Metabase dashboards notebook Jupyter, Hex, Observable notebooks analysis Ad-hoc analysis or one-off reports ml model Machine learning models trained on dbt outputs application Customer-facing apps or internal tools source (rare) another data source consuming your models
Maturity Levels
Maturity Meaning -------- ------- low Experimental, not widely used, may change medium Stable but not mission-critical high Mission-critical, used in executive reporting
Multiple Exposures in One File
version: 2
exposures:
- name: revenue_dashboard
type: dashboard
maturity: high
depends_on:
- ref('fct_orders')
- ref('dim_customers')
owner:
name: Finance Team
email: finance@company.com
- name: churn_prediction_model
type: ml model
maturity: medium
url: https://mlflow.company.com/experiments/42
description: "Weekly churn prediction model trained on customer behavior data."
depends_on:
- ref('fct_sessions')
- ref('dim_customers')
- ref('fct_orders')
owner:
name: Data Science Team
email: datascience@company.com
- name: customer_portal
type: application
maturity: high
description: "Customer-facing portal showing order history."
depends_on:
- ref('fct_orders')
- ref('dim_customers')
owner:
name: Engineering Team
email: eng@company.com
Exposures in the Lineage Graph
Exposures appear in the dbt docs lineage graph as orange nodes at the far right of the DAG, downstream of your mart models:
[source: shopify.orders]
|
v
[stg_orders]
|
v
[fct_orders] ──────────────────── [Revenue Dashboard] (orange node)
| owner: Finance Team
v
[fct_revenue_monthly] ─────────── [Executive Report] (orange node)
Click an exposure node in the docs site to see its full description, URL, owner, and all the models it depends on.
Selecting by Exposure
Run all models that feed a specific exposure:
# Run all models upstream of the revenue dashboard dbt run --select +exposure:revenue_dashboard # Test all models that the churn model depends on dbt test --select +exposure:churn_prediction_model # List all nodes used by all exposures dbt ls --select +exposure:*
This selection is particularly useful before a release: run all models that feed production dashboards and ensure their tests pass before deploying.
Source References in Exposures
Exposures can also reference source tables directly if a consumer reads raw data:
depends_on:
- ref('fct_orders')
- source('ecommerce', 'raw_products') ← references a source directly
Best Practices
- Define an exposure for every dashboard or report used in leadership meetings
- Set
maturity: highfor anything used in financial reporting or executive decisions - Always include an owner email so there is a clear point of contact when something breaks
- Add the URL to the dashboard so teammates can click directly from the docs site
- Run
dbt run --select +exposure:*in your CI job to validate all models feeding exposures
