dbt Exposures: Exposure Lineage, Selectors — dbt Developer Hub
dbt exposures connect dashboards, notebooks, and apps to the dbt DAG. Learn how to define, automate, and use them for safe changes and clear lineage.
On this page · 22 sections
- What is an exposure in dbt?
- Why exposures matter (and when they pay off immediately)
- Exposures in dbt: patterns that scale
- Automating exposures
- Selectors, CI, and partial builds
- Best practices for exposures
- Exposures vs. other documentation tools
- End-to-end example: shipping a change safely
- FAQ: exposures and adjacent questions
- How and why use exposures?
- Is it testing the model or the exposure?
- Q1 - Should I state the whole downstream of tables or just the direct tables that it depends on?
- Q3 - What’s the purpose of dbt run -m exposure:name and dbt test -m exposure:name?
- What are some common use cases for dbt?
- What does dbt stand for?
- Is dbt better than Databricks?
- Is dbt an ETL tool?
- Ready to Crush the dbt Certified Developer Exam?
- Want to learn more about how to leverage dbt Cloud’s features?
- Implementation tips and related resources
- A few gotchas to avoid
- Where exposures fit in the bigger picture
- Topic
- dbt for Analytics Engineers
- Category
- dbt
dbt exposures document the downstream dashboards, ML notebooks, and apps that rely on your transformed tables. You declare each exposure in YAML, point it at the dbt models it depends_on, give it a url, owner, and description, and it becomes a first-class node in the DAG. The immediate payoff: clear lineage in dbt docs, faster impact analysis, targeted dbt run/dbt test with selectors, and better visibility for data consumers. Below you’ll see concrete patterns for defining exposures, practical examples (Looker/Tableau), automation ideas, and answers to the questions engineers ask most.
What is an exposure in dbt?
An exposure is a lightweight record that tells dbt, “this downstream asset is powered by these upstream resources.” Exposures show up as nodes in the DAG and on the docs site. They’re ideal for any downstream use of your dbt models: a BI dashboard, a forecasting notebook in data science, an internal service endpoint, or a stakeholder report. In short, exposures make downstream use explicit and auditable.
# models/marts/finance/_exposures.yml
version: 2
exposures:
- name: revenue_dashboard
type: dashboard
url: https://bi.company.com/dashboards/revenue
maturity: high
owner:
name: Finance Analytics
email: finance-analytics@company.com
description: >-
Executive revenue dashboard with weekly and daily breakdowns.
depends_on:
- ref('fct_orders')
- ref('dim_customers')
tags: ['finance', 'kpi', 'executive']
Notes:
- type accepts dashboard, notebook, analysis, or application.
- url points to the asset (bi tool link, doc, or internal app).
- depends_on uses
ref()/source()to capture the true dependency graph. - Config lives alongside your dbt project, versioned like code.
Once committed, exposures will appear in your documentation site when you generate dbt docs. In dbt Cloud or any hosted docs, you’ll see the exposure node, its upstream lineage, owners, and description.
Why exposures matter (and when they pay off immediately)
Imagine your orders model serves a revenue dashboard and has 40M rows. You need to change a join to order_items. With an exposure that targets the dashboard, you can do targeted runs/tests and tight impact checks before a deploy:
# List what would be affected
$ dbt ls -s exposure:revenue_dashboard
# Build all upstream nodes required for the exposure
$ dbt run -m exposure:revenue_dashboard
# Run tests that touch the exposure's upstream graph
$ dbt test -m exposure:revenue_dashboard
That one exposure gives you a safe path to validate the change without rebuilding the entire DAG. It also tells on-call engineers exactly which downstream assets could be at risk if an upstream change goes sideways.
Exposures in dbt: patterns that scale
For most teams, defining exposures at the mart layer is the sweet spot. Let the DAG carry transitive dependencies; you don’t need to list every staging model. A clear exposure per dashboard (or per major section) usually maps best to how stakeholders think.
# models/marts/marketing/_exposures.yml
version: 2
exposures:
- name: looker_customer_ltv
type: dashboard
url: https://looker.company.com/dashboards/123
owner:
name: Growth BI
email: growth-bi@company.com
depends_on:
- ref('fct_customer_ltv')
- name: tableau_campaign_roas
type: dashboard
url: https://tableau.company.com/views/ROAS/Overview
owner:
name: Marketing Ops
email: mops@company.com
depends_on:
- ref('fct_campaign_performance')
Those two lines of YAML per exposure buy you searchable documentation, a stable selector for CI, and accountable ownership details. Exposures in the dbt docs also help new teammates understand how dbt models are used downstream during onboarding.
Automating exposures
You can create exposures manually, but for larger orgs, automation keeps the list fresh. Two common approaches:
- BI API sync. Pull dashboard metadata from Looker/Tableau APIs (titles, ids, owners, URLs), map them to mart models, and emit YAML. Commit via a bot PR.
- Code generation from lineage. If you maintain a mapping of model-to-dataset-to-dashboard, generate exposure blocks nightly to capture new downstream assets.
# pseudo-script outline (Python)
bi_dashboards = fetch_bi_dashboards() # includes url, owner, title
model_map = read_model_to_dataset_map()
exposures = []
for d in bi_dashboards:
depends = infer_depends_on(d, model_map) # returns ["ref('fct_...')"]
exposures.append({
'name': slugify(d['title']),
'type': 'dashboard',
'url': d['url'],
'owner': {'name': d['owner_name'], 'email': d['owner_email']},
'depends_on': depends
})
write_yaml('models/_exposures.generated.yml', {'version': 2, 'exposures': exposures})
Start small: automate a single domain (e.g., Finance) and expand once you trust the mapping. If you’re using dbt Cloud, hosting the docs site alongside the repo makes this workflow smooth for your data team.
Selectors, CI, and partial builds
Selectors unlock precise builds around an exposure. Wire them into CI to prove safety before merging:
# Example GitHub Actions step
- name: Build the graph for exec revenue exposure
run: |
dbt deps
dbt seed --select state:modified+ # optional
dbt run -m exposure:revenue_dashboard
dbt test -m exposure:revenue_dashboard
This optimizes the pipeline and keeps validation focused on what the dashboard actually queries. It’s also friendly for UAT: share the exposure url with owners, then rebuild just the upstream graph after fixes.
Best practices for exposures
- Define one exposure per meaningful dashboard, ML notebook, or app page; avoid catch-all buckets—this is the core best practices pattern.
- Point
depends_onat marts; the DAG will capture upstream staging/intermediate lineage. - Always set
url, owner name/email, and a one-sentence description for quick triage. - Use tags for domain routing (e.g.,
finance,marketing,ml). - Keep the exposure file close to the domain models it references.
- Gate merges by running
dbt test -m exposure:*in CI for high-maturity domains. - For semantic metrics, pair exposures with the dbt’s Semantic Layer but don’t duplicate ownership details.
- Use ref() vs source() correctly so lineage is accurate.
Exposures vs. other documentation tools
| Option | Strength | Weakness | When to choose |
|---|---|---|---|
| Exposure (dbt) | Tight DAG integration, selectors, owners | Needs basic YAML upkeep or automation | Link dashboards/apps to models and enable targeted runs/tests |
| BI folder docs | Close to data consumers | No build-time lineage to dbt models | Stakeholder how-tos and visuals |
| Data catalog | Broad enterprise metadata | May not drive dbt selectors | Cross-platform governance |
| Runbooks/tickets | Operational context | Not connected to DAG | Procedures and on-call steps |
Use exposures to wire the DAG to downstream assets; keep catalogs and BI docs for policy and UX details.
End-to-end example: shipping a change safely
Scenario: You’re updating fct_orders window logic; two executive dashboards depend on it. You’ve declared one exposure per dashboard and added owners. Before merging:
- Branch and adjust SQL in
fct_orders. dbt run -m exposure:revenue_dashboardto build all upstream nodes feeding the exposure.dbt test -m exposure:revenue_dashboardto validate tests along the path.- Share the exposure
urlwith owners for UAT in the bi tool. - Merge when owners sign off; add a note in the exposure
descriptionif helpful.
This keeps the pipeline focused on what matters and avoids rebuilding unrelated parts of the DAG.
FAQ: exposures and adjacent questions
How and why use exposures?
Define exposures to connect downstream assets to upstream models. Benefits: clear lineage, targeted selectors for dbt run/dbt test, owner accountability, and faster impact analysis. Put the YAML next to the domain models, and keep depends_on pointed at marts.
Is it testing the model or the exposure?
When you run dbt test -m exposure:name, dbt selects the upstream nodes referenced by the exposure and runs tests on those resources. You’re not testing the exposure itself; you’re testing the models and other nodes in its selected graph.
Q1 - Should I state the whole downstream of tables or just the direct tables that it depends on?
In an exposure, declare the direct dbt models your asset relies on (usually marts). Do not list every staging table; the DAG infers transitive lineage. This keeps the exposure minimal while preserving complete dependency context.
Q3 - What’s the purpose of dbt run -m exposure:name and dbt test -m exposure:name?
These selectors compile the exposure’s upstream graph so you can build and validate exactly what powers that asset—great for impact checks, UAT, and domain-scoped CI.
What are some common use cases for dbt?
- Transform warehouse tables for analytics marts
- Codify business logic for BI dashboards and reports
- Prepare features for data science notebooks and jobs
- Standardize and test data quality
What does dbt stand for?
dbt stands for Data Build Tool.
Is dbt better than Databricks?
They’re different categories: dbt focuses on SQL-first transformation and testing; Databricks is a Spark-based lakehouse platform. Many teams use them together. Pick based on your primary workloads and team skills.
Is dbt an ETL tool?
dbt is not an ETL tool; it runs the “T” in ELT inside your warehouse/lakehouse. Use ingestion tools for extract/load, then model data using dbt.
Ready to Crush the dbt Certified Developer Exam?
Review foundational topics on the dbt topic hub, practice selectors and DAG reasoning with exposures, and drill into refs/sources here: model-to-table references explained.
Want to learn more about how to leverage dbt Cloud’s features?
Host your docs site in dbt Cloud, wire exposures into CI, and standardize owners. For reference material, the official docs cover exposures well: dbt docs: exposures.
Implementation tips and related resources
- Keep your domain config tidy; see dbt project structure best practices for file placement—then link exposures nearby.
- If your metrics live above models, read the dbt Semantic Layer guide to place exposures and metrics cleanly.
- For historical dimensions that feed dashboards, skim our short SCD summary and deep dive here: Slowly Changing Dimension primer.
- Explore lineage and snapshots powering dashboards: dbt snapshots (dbt developer hub).
A few gotchas to avoid
- Don’t set
depends_onto raw warehouse tables; reference your modeled layer so the graph is accurate. - Don’t over-specify. One exposure per dashboard page or ML job is enough. Let the DAG expand upstream.
- Don’t skip owners. When something breaks, the right inbox matters more than any tag.
- Include a short documentation note for context if owners change or the dashboard moves urls.
Where exposures fit in the bigger picture
Exposures are the thin connective tissue from the dbt DAG to downstream assets. They don’t replace a data catalog or BI documentation, but they uniquely power selectors and connect changes to impact at build time. With a small amount of YAML, you get auditable lineage, safer deploys, and higher visibility into downstream use. That’s leverage for any data team using dbt.
Extended notes: defining exposures is covered in the dbt developer hub, and exposures in the dbt ecosystem are designed to be simple so they don’t slow you down. Add just enough metadata for owners, keep URLs fresh, and let automation help as your footprint grows. With this, the downstream use of your dbt becomes first-class, and your DAG tells the full story—from upstream sources to the last dashboard tile (bi).
Before you leave: try the free graded practice exercises at /practice.
- dbt
dbt Seeds & the dbt seed: A dbt Developer Hub Guide
Learn how to use dbt seeds to turn small CSV files into reliable, version-controlled tables in your warehouse. Clear use cases, configs, and examples.
- dbt
dbt Date Spine: Build a Calendar Hub Table
Build a reliable dbt date spine and calendar hub table fast. Use dbt_utils, variables for start/end dates, and proven patterns that scale.
- dbt
dbt Exposures: Exposure Lineage, Selectors — dbt Developer Hub
dbt exposures connect dashboards, notebooks, and apps to the dbt DAG. Learn how to define, automate, and use them for safe changes and clear lineage.
