Data Engineering  /  dbt

๐Ÿ”„ dbt โ€” Data Build Tool 60 guides ยท updated 2026

Analytics engineering with SQL โ€” models, tests, sources, and Jinja macros that turn raw warehouse tables into trustworthy, documented data products.

The dbt Semantic Layer: One Place for All Your Metrics

Every data team eventually runs into the same problem. The sales dashboard shows 4.2MrevenueforQ3,thefinancereportshows4.2M revenue for Q3, the finance report 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 notebook

Tools 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

models/semantics/sem_orders.yml
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: foreign

The 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:

models/semantics/metrics.yml
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: revenue

Three metric types are available:


Querying the Semantic Layer

Once metrics are defined, you can query them from multiple places.

dbt CLI

Terminal window
mf query \
--metrics revenue \
--group-by metric_time__month,region \
--order metric_time__month

MetricFlow 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:


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: reporting

Running 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:

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:

Terminal window
# Install with your warehouse adapter
pip install dbt-core dbt-snowflake
# Add MetricFlow to your project packages

In packages.yml:

packages:
- package: dbt-labs/metricflow
version: [">=0.7.0", "<1.0.0"]

Then run dbt deps to install.

Validate your semantic definitions:

Terminal window
mf validate-configs

This 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.sql
select
order_id,
customer_id,
order_date,
region,
status,
amount_usd
from {{ 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:

Terminal window
mf query --metrics total_revenue --group-by metric_time__month,region

Every 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:

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.