Lineage integrity · rule model-possibly-unused
dbt exposures: what they are and how to declare them
A dbt exposure is a YAML entry naming something outside dbt that uses your models, such as a dashboard, notebook or application. It adds that consumer to your lineage, with an owner.
A Metacenta review checks this under the rule Leaf models are consumed by something. Everything below applies whether or not you ever commission one.
What a dbt exposure does
dbt can't see who reads its models. An exposure records that link, so you can trace a model change to the dashboard it affects and know who to tell.
How to declare an exposure
Add an exposures: key to a .yml file under models/. Three fields are required: name, type and owner, which needs a name or an email. List what it reads under depends_on.
exposures:
- name: weekly_revenue
type: dashboard
maturity: high
url: https://bi.example.com/dashboards/1
owner:
name: Finance analytics
depends_on:
- ref('fct_orders')
type is one of dashboard, notebook, analysis, ml or application. maturity is optional and takes high, medium or low.
How to run everything an exposure needs
Select the exposure with + to include everything upstream of it.
dbt run -s +exposure:weekly_revenue
dbt test -s +exposure:weekly_revenue
See dbt's exposures docs for every property.
What this rule checks
This rule flags dbt models that no other model reads and that no exposure, metric or semantic model declares as a consumer. It runs only when the project declares at least one of those three, and declines otherwise. Superseded model versions are left out. So is a MetricFlow time spine, when the project has a semantic layer.
Why it matters
If nothing reads a leaf model, it costs build time and warehouse storage for no return. A dashboard that reads it without a declared exposure looks identical, so we report the finding at low confidence.
How to fix it
Declare exposures for leaf models, or retire them. Declare an exposure for each dashboard or application that reads the model. Drop the model if nothing does.
Before:
models:
- name: fct_orders
description: One row per order.
After:
models:
- name: fct_orders
description: One row per order.
exposures:
- name: weekly_revenue
type: dashboard
owner:
name: Finance analytics
depends_on:
- ref('fct_orders')
When it is fine to leave
A mart read only by a BI tool, in a team that does not yet declare exposures, is the common case. The gap is then a missing declaration, not waste. We rate it low severity in a marts or reporting folder for that reason, and medium elsewhere.
What we need to check it
manifest.json alone, which dbt parse writes. We list the superseded versions and time spines we left out, so the exclusion is visible rather than silent.