Metacenta

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.