How the dbt Semantic Layer solves the problem of inconsistent metric definitions across BI tools — defining metrics once in dbt, exposing them through a unified API, and ensuring every tool that queries your data gets the same answer to the same business question.
The dbt Semantic Layer addresses one of the most persistent problems in enterprise analytics: the same business metric means different things in different tools. Revenue in Salesforce dashboards differs from revenue in the data warehouse because of subtle differences in how each tool aggregates and filters. Active customers in the executive dashboard are counted differently than in the marketing attribution report. These inconsistencies erode trust in analytics, generate unproductive reconciliation exercises, and force every analyst to re-implement every metric calculation independently.
The dbt Semantic Layer solves this by defining metrics once — in dbt — and exposing them through a standardised API that any connected BI tool can query. Instead of each tool reimplementing revenue calculation logic, every tool queries the semantic layer and gets the same answer.
What the Semantic Layer Is
The dbt Semantic Layer is a service that sits between your data warehouse and your BI tools. It exposes defined metrics and dimensions as a queryable API, using the MetricFlow engine to translate metric queries into optimised SQL that runs against your warehouse.
The semantic layer is not a data store — it does not cache or store metric values. It is a translation layer: a query for "monthly revenue by region" is translated into the appropriate SQL, run against the warehouse, and the result returned to the BI tool.
**MetricFlow** is the open-source query engine underlying the dbt Semantic Layer. MetricFlow understands the relationships between metrics, dimensions, and entities defined in your dbt project and generates correct SQL for any combination of metrics and dimensions a user requests.
Defining Metrics in dbt
Metrics are defined in YAML files in your dbt project, alongside the models they are calculated from.
A metric definition specifies:
- The **type** of metric (simple, ratio, cumulative, derived)
- The **measure** (the aggregation: sum, count, count_distinct, average)
- The **model** the metric is calculated from
- The **dimensions** the metric can be sliced by
- Any **filters** that should always apply
metrics:
- name: monthly_revenue
description: "Net revenue after returns, excluding internal test orders"
type: simple
label: "Monthly Revenue"
type_params:
measure:
name: net_revenue
agg: sum
agg_time_dimension: order_date
filter: |
{{ Dimension('order__is_test_order') }} = false
This definition is the single source of truth for "monthly_revenue." Every tool that queries this metric through the semantic layer uses this definition.
Metric types:
Simple metrics aggregate a single measure: SUM(revenue), COUNT(orders), COUNT_DISTINCT(customers).
Ratio metrics divide one measure by another: conversion_rate = sessions_resulting_in_purchase / total_sessions.
Cumulative metrics aggregate over a rolling window: rolling_28_day_active_users.
Derived metrics are expressions combining other metrics: gross_margin = (revenue - cost) / revenue.
Semantic Models: The Data Layer
Metrics are calculated from semantic models — structured representations of your dbt models that describe the entities, dimensions, and measures available.
A semantic model specifies:
- The **model** (the dbt model it reads from)
- **Entities** (the primary and foreign keys that define relationships — customer_id, order_id, product_id)
- **Dimensions** (attributes for slicing — region, product_category, acquisition_channel)
- **Measures** (the raw aggregations before they become metrics — revenue, order_count, session_count)
semantic_models:
- name: orders
model: ref('fct_orders')
entities:
- name: order
type: primary
expr: order_id
- name: customer
type: foreign
expr: customer_id
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
- name: region
type: categorical
- name: product_category
type: categorical
measures:
- name: net_revenue
agg: sum
expr: revenue - returns
MetricFlow uses entity relationships to construct correct joins when a metric query involves dimensions from multiple semantic models — for example, a revenue metric sliced by a customer acquisition channel attribute that lives in the customer semantic model.
How Tools Query the Semantic Layer
The dbt Semantic Layer exposes metrics through a JDBC/ADBC API. BI tools connect to this API as they would to a data warehouse — using a driver and connection credentials. The tool issues a query (in a semantic query format) and receives the metric values back.
**Native integrations** exist for several BI tools: Tableau (via connector), Hex, Mode, and others. These native integrations surface dbt metrics as first-class objects in the tool — users browse and select metrics from a catalogue rather than writing SQL.
**Semantic Layer API for custom tools:** for tools without native integration, the dbt Semantic Layer provides an API (GraphQL and ADBC) that developers can integrate against directly. This allows internal applications, data science notebooks, and custom dashboards to access metrics from the semantic layer.
**Metricflow in development:** during development, MetricFlow's CLI allows you to validate metric definitions, preview SQL generated for a given metric query, and test metrics against your warehouse before deploying to production.
Governance Benefits
The semantic layer fundamentally changes the governance model for metric definitions:
**Single source of truth.** The metric definition is in dbt, version-controlled, code-reviewed, and testable. Not in a BI tool's proprietary configuration, not in a spreadsheet, not distributed across three different tool-specific implementations.
**Changes are tracked.** When the definition of "active customer" changes (from 30-day to 90-day login window), the change is a git commit with an author, a date, and a review. Every tool that queries the metric immediately uses the new definition.
**Downstream impact visibility.** dbt's lineage shows which dashboards and reports reference each metric. A proposed metric definition change is accompanied by visibility into exactly what downstream content will be affected.
**Analyst productivity.** Analysts query metrics without needing to know the SQL, the join logic, or the filter conditions. The semantic layer is a self-service catalogue of trusted metrics — analysts browse, select, and combine without implementation work.
When to Implement the Semantic Layer
The dbt Semantic Layer is most valuable for organisations where:
- Multiple BI tools are in use (Tableau for operations, Power BI for finance, Hex for data science) and metric consistency across tools is a problem
- Analyst time is consumed by re-implementing metric calculations in different tools
- Trust in analytics is low because different dashboards give different answers to the same question
- The data team wants to own metric definitions rather than delegating them to BI tool administrators
For smaller organisations with a single BI tool and a small team, the semantic layer adds governance overhead that may not yet justify the investment. The metric consistency problem becomes acute at scale — when there are many metrics, many users, and multiple tools.
For organisations building on dbt and evaluating the semantic layer, our data architecture consulting team can assess readiness and design the implementation — contact us to discuss your analytics infrastructure.
A former Microsoft data architect audits your data foundation, identifies your top priorities, and sends you a written plan. Free. No pitch.
Book a Call →