The dbt Semantic Layer: One Place for All Your Metrics
Every data team eventually runs into the same problem. The sales dashboard shows 4.1M, and the weekly email shows $4.4M. All three are querying the same warehouse, but the numbers are different because each tool applies its own logic โ different filters, different date truncations, different join paths.
The dbt Semantic Layer was built to solve exactly this. Instead of letting every downstream tool define its own metric logic, you define metrics once in dbt and expose them through a consistent API that every tool queries the same way.
What the Semantic Layer Actually Is
The dbt Semantic Layer sits between your dbt models and your BI or analytics tools. It is powered by MetricFlow โ dbtโs metric definition framework โ which was fully integrated into dbt Core starting with v1.6 and has matured significantly through 2024 and 2025.
Raw warehouse tables | v dbt models (SQL transformations) | v Semantic layer (MetricFlow metric definitions) | v Consistent metric API / | \Tableau Hex Python notebookTools that connect to the Semantic Layer send queries in a natural language-like format. MetricFlow translates those into optimized SQL that runs against your warehouse, applies the metric definition consistently, and returns results. The SQL generation is handled for you.
Semantic Models and Metrics
The Semantic Layer introduces two new YAML concepts: semantic models and metrics.
Semantic models describe the grain and dimensions of a dataset. They map to dbt models you have already built.
Metrics define how to calculate a business number using those semantic models.
Defining a Semantic Model
semantic_models: - name: orders description: "Order-level data with revenue and status" model: ref('fct_orders') defaults: agg_time_dimension: order_date
dimensions: - name: order_date type: time type_params: time_granularity: day - name: region type: categorical - name: status type: categorical
measures: - name: order_count agg: count expr: order_id - name: total_revenue agg: sum expr: amount_usd - name: avg_order_value agg: average expr: amount_usd
entities: - name: order_id type: primary - name: customer_id type: foreignThe semantic model does not hold any SQL logic itself. It describes what columns exist in your fct_orders model and how they should be interpreted โ which are dimensions, which are measures, which are time fields.
Defining Metrics
Once the semantic model exists, metrics reference it:
metrics: - name: revenue description: "Total revenue from completed orders" type: simple type_params: measure: total_revenue filter: | {{ Dimension('orders__status') }} = 'completed'
- name: monthly_active_customers description: "Distinct customers placing an order in a calendar month" type: simple type_params: measure: order_count label: "Monthly Active Customers"
- name: revenue_growth_mom description: "Month-over-month revenue growth rate" type: derived type_params: expr: (revenue - lag(revenue, 1)) / lag(revenue, 1) metrics: - name: revenueThree metric types are available:
- simple โ a single measure, optionally filtered
- ratio โ numerator divided by denominator
- derived โ calculated from other metrics using an expression
Querying the Semantic Layer
Once metrics are defined, you can query them from multiple places.
dbt CLI
mf query \ --metrics revenue \ --group-by metric_time__month,region \ --order metric_time__monthMetricFlow generates the SQL, sends it to your warehouse, and returns results. You do not write the SQL yourself.
Python / dbt Cloud API
In dbt Cloud, metrics are available via the Semantic Layer API. You can query them from Python:
import dbtsl
client = dbtsl.SemanticLayerClient( environment_id="your_env_id", auth_token="your_token", host="semantic-layer.cloud.getdbt.com")
results = client.query( metrics=["revenue", "order_count"], group_by=["metric_time__month", "region"],)The same metric definitions drive the result regardless of which tool calls the API.
BI Tool Integration
Tools like Tableau, Looker, Hex, and Mode connect directly to the dbt Semantic Layer API. When an analyst drags โRevenueโ onto a chart, the tool sends a query through MetricFlow rather than generating its own SQL. This is why all tools get the same number โ they are all calling the same metric definition.
Why Centralized Metric Definitions Matter
The old approach was to define revenue inside each BI tool. The Looker LookML had one definition, the Tableau calculated field had another, and the Jupyter notebook had a third. When the definition needed to change โ say, to exclude refunds โ someone had to update it in every single place, and inevitably one would be missed.
With the Semantic Layer:
- Metric logic lives in one YAML file, version-controlled in your dbt project
- A change to the definition propagates to every connected tool automatically
- Analysts can explore metrics without needing to know SQL
- dbt generates optimized SQL that takes advantage of your warehouseโs query engine
Saved Queries
In 2024, dbt introduced saved queries as a way to pre-define common metric combinations that tools can discover and use directly.
saved_queries: - name: weekly_revenue_by_region description: "Revenue by region at weekly granularity for dashboards" query_params: metrics: - revenue - order_count group_by: - metric_time__week - region exports: - name: weekly_revenue_by_region_export config: export_as: table schema: reportingRunning dbt sl export materializes these saved queries as tables in your warehouse, which works well for dashboards that need fast query performance.
MetricFlow in dbt Core vs dbt Cloud
MetricFlow is available in dbt Core, but with some differences from the dbt Cloud experience.
With dbt Core, you can define semantic models and metrics and use the mf CLI to query them locally. The warehouse connection and SQL generation work fully.
With dbt Cloud, you additionally get:
- The Semantic Layer API that BI tools can connect to directly
- Saved query exports managed through dbt Cloud scheduling
- The dbt Explorer lineage view that shows metric definitions alongside model lineage
- Usage tracking for which metrics and dimensions are actually being queried
For most teams doing serious metric governance work, dbt Cloudโs managed API is what makes the Semantic Layer operationally practical.
Setting Up MetricFlow
If you are starting from scratch:
# Install with your warehouse adapterpip install dbt-core dbt-snowflake
# Add MetricFlow to your project packagesIn packages.yml:
packages: - package: dbt-labs/metricflow version: [">=0.7.0", "<1.0.0"]Then run dbt deps to install.
Validate your semantic definitions:
mf validate-configsThis checks that your semantic models reference valid columns, that metric measures exist, and that entity relationships are consistent.
A Practical Example: E-Commerce Revenue Tracking
Here is how a complete setup looks for a basic e-commerce scenario.
Underlying model:
-- models/marts/fct_orders.sqlselect order_id, customer_id, order_date, region, status, amount_usdfrom {{ ref('int_customer_orders') }}Semantic model and metrics:
semantic_models: - name: orders model: ref('fct_orders') defaults: agg_time_dimension: order_date dimensions: - name: order_date type: time type_params: time_granularity: day - name: region type: categorical measures: - name: revenue agg: sum expr: amount_usd entities: - name: order_id type: primary
metrics: - name: total_revenue type: simple type_params: measure: revenue filter: "{{ Dimension('orders__status') }} = 'completed'"Query via CLI:
mf query --metrics total_revenue --group-by metric_time__month,regionEvery tool querying total_revenue through the Semantic Layer will run this exact logic โ filtered to completed orders, grouped the same way, returning the same number.
When to Use the Semantic Layer
The Semantic Layer adds the most value when:
- Multiple BI tools or teams are querying the same metrics
- Metric definitions are changing frequently (new business rules, new exclusions)
- You want analysts to explore data without writing raw SQL
- You need auditability โ the ability to trace exactly what SQL ran for a given metric
It is less necessary for small teams using a single BI tool with stable metrics that rarely change. In those cases, defining metrics directly in the BI tool is simpler to set up, even if it is less rigorous long-term.
The trend in 2025 is toward the Semantic Layer becoming a standard part of mature analytics stacks. As more BI tools add native dbt Semantic Layer connectors and as MetricFlow stabilizes further, the barrier to adoption has dropped considerably compared to early releases.