Part 19. Semantic Layer, Metrics and Exposures
A semantic layer emerges when the same metrics start being used across multiple reports, applications, or teams. Until that point, clear data marts and check facts are enough. But once total_balance_rub, active consent, or risk_event_count repeat downstream of the consumption chain, their definitions need to be centralized.
What a metric is
A metric is not just a column. It is a name, a formula, grain, filters, freshness, an owner, and a list of consumers. If two reports compute "active customers" using different rules, the problem is not the BI tool — it is the semantic contract.
dbt semantic models
dbt supports semantic models and metrics, but in the learning track we are not required to enable the full layer. First, you need to write down the semantic intent:
Metric: active_consent_count
Source mart: mart_open_api_consents
Definition: number of consents where `revoked_at is null`
Grain: `scope`
Consumer: Open API monitoring
After that, you can decide whether a dbt semantic layer is needed or a documented mart is sufficient.
Exposures
An exposure shows who reads a data product: a dashboard, an API, a notebook, a report. This matters for contract drift. If a mart has an exposure, breaking changes must notify the downstream consumer owner.
Qwen prompt
Read the marts and specs.
Find fields that look like shared metrics.
For each, propose a definition, grain, owner, consumer, and check fact.
Do not create semantic models without confirmation.
Minimum output
Create a semantic registry:
# Semantic Registry
## total_balance_rub
Definition:
Grain:
Owner:
Consumers:
Check:
Breakdown for the reader
The semantic layer is worth introducing not because it is part of a modern stack, but because without it repeated metrics start to drift apart. While a mart is used by a single report, definitions can live next to the mart. When the same field appears across multiple teams, a new contract emerges: what exactly active_consent_count means, who owns the definition, what grain the metric has, what filters are applied.
It is important not to confuse the semantic layer with a catalog of pretty names. A metric is not a column renamed. It is a formula, context, constraints, and consumers. If one team counts active consent by null in revoked_at, while another excludes old consents by date, the organization already has two metrics sharing one name. The problem did not arise in BI — it arose from the lack of an explicit semantic contract.
In the learning project, you may skip the full semantic layer. This is a deliberate limitation. First, you need to learn how to write down the intent: field, definition, grain, owner, consumers, check. Only after that does it make sense to decide whether a Markdown registry is enough or a dbt semantic model is required. Otherwise the team will end up with yet another layer of YAML without an agreed meaning.
Exposures add a consumer outline. They show who reads the mart: a dashboard, a notebook, an API, a regular report. This affects breaking changes. If a mart has no consumer, a change looks local. If an exposure is recorded, the author sees who will be affected by a field rename or a grain change. This is how the semantic layer becomes part of SDD rather than a separate mart of terms.
Practice
Pick one metric from the marts and fill in the semantic registry. If you cannot name an owner or a consumer, do not add a semantic model — first clarify the product promise.
Common mistake
Adding a semantic layer for the sake of stack completeness. If there are no multiple consumers and no repeated metrics, the layer becomes bureaucracy. But if consumers already exist, its absence will cause drift.
Check questions
- How is a metric different from a column?
- When does an exposure make a change breaking?
- Why is it not worth enabling a semantic layer before shared metrics appear?