A curated collection of Agent Skills for working with dbt, to help AI agents understand and execute dbt workflows more effectively.
65
82%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Risky
Do not use without reviewing
This is the authoring guide for the latest dbt Semantic Layer YAML spec, supported in dbt Core 1.12+ and Fusion (always).
In the latest spec, semantic models are configured as metadata annotations on your dbt models rather than as separate top-level resources. Measures are replaced by simple metrics defined directly within models.
Add a semantic_model: block to the model's YAML with enabled: true. Set agg_time_dimension at the model level to the primary time column. If the model does not have a time column, warn the user that it cannot contain time-based metrics. Ask the user if they want to create a derived time dimension.
models:
- name: orders
semantic_model:
enabled: true
agg_time_dimension: ordered_atIdentify the primary key column (check for _id suffix, uniqueness tests, or explicit config). Add an entity: block to that column's entry. If the model has foreign keys, define those as entity: type: foreign.
models:
- name: orders
semantic_model:
enabled: true
agg_time_dimension: ordered_at
columns:
- name: order_id
entity:
type: primary
name: order
- name: customer_id
entity:
type: foreign
name: customerEntity types: primary, foreign, unique, natural (SCD Type II only).
Scan columns for dimension candidates:
dimension: type: time with granularity at the column leveldimension: type: categoricalPresent suggested dimensions to user for confirmation.
models:
- name: orders
semantic_model:
enabled: true
agg_time_dimension: ordered_at
columns:
- name: order_id
entity:
type: primary
name: order
- name: customer_id
entity:
type: foreign
name: customer
- name: ordered_at
granularity: day
dimension:
type: time
- name: order_status
dimension:
type: categoricalCreate simple metrics for the model. For each metric, collect: name, description, label, aggregation type, and expression. Supported agg types: sum, min, max, average, median, count, count_distinct, percentile, sum_boolean.
models:
- name: orders
semantic_model:
enabled: true
agg_time_dimension: ordered_at
columns:
- name: order_id
entity:
type: primary
name: order
- name: customer_id
entity:
type: foreign
name: customer
- name: ordered_at
granularity: day
dimension:
type: time
- name: order_status
dimension:
type: categorical
metrics:
- name: order_count
type: simple
label: Order Count
agg: count
expr: 1
- name: total_revenue
type: simple
label: Total Revenue
agg: sum
expr: amount
- name: average_order_value
type: simple
label: Average Order Value
agg: avg
expr: amountUse the derived_semantics block for dimensions or entities that are not a direct 1:1 mapping to a physical column. The expr field is required.
models:
- name: orders
[...]
derived_semantics:
dimensions:
- name: order_size_bucket
type: categorical
expr: "case when amount > 100 then 'large' else 'small' end"
label: "Order Size"
entities:
- name: user
type: foreign
expr: "substring(id_order from 2)"Simple metrics support these additional properties:
models:
- name: orders
[...]
metrics:
- name: customers
type: simple
label: Count of customers
agg: count
expr: customers
fill_nulls_with: 0 # Replace nulls with this value
join_to_timespine: true # Join to time spine to fill missing dates
agg_time_dimension: my_other_time_column # Override model's default time dimension
filter: "{{ Dimension('customer__customer_total') }} >= 20"For percentile aggregation:
models:
- name: orders
[...]
metrics:
- name: revenue_p95
type: simple
label: Revenue P95
agg: percentile
expr: amount
percentile: 95.0
percentile_type: discrete # discrete or continuousSimple metrics defined within a model serve as building blocks. Advanced metrics that reference simple metrics within the same model go under the model's metrics: key. Advanced metrics that reference metrics across different models go under the top-level metrics: key.
Combine multiple metrics using an expression.
models:
- name: orders
[...]
metrics:
- name: order_gross_profit
description: "Gross profit from each order."
label: Order gross profit
type: derived
expr: revenue - cost
input_metrics:
- name: order_total
alias: revenue
- name: order_cost
alias: costWith offset window (period-over-period):
models:
- name: orders
[...]
metrics:
- name: order_total_growth_mom
description: "Percentage growth of orders compared to 1 month ago"
label: Order total growth % M/M
type: derived
expr: (order_total - order_total_prev_month) * 100 / order_total_prev_month
input_metrics:
- name: order_total
- name: order_total
alias: order_total_prev_month
offset_window: 1 monthWith filter on input metric:
models:
- name: orders
[...]
metrics:
- name: food_order_gross_profit
label: Food order gross profit
type: derived
expr: revenue - cost
input_metrics:
- name: order_total
alias: revenue
filter: |
{{ Dimension('order__is_food_order') }} = True
- name: order_cost
alias: cost
filter: |
{{ Dimension('order__is_food_order') }} = TrueAggregate a metric over a running window or grain-to-date period. Requires a time spine.
metrics:
- name: cumulative_order_total
label: "Cumulative order total (All-Time)"
description: "The cumulative value of all orders"
type: cumulative
input_metric: order_total
- name: cumulative_order_total_l1m
label: "Cumulative order total (L1M)"
description: "Trailing 1-month cumulative order total"
type: cumulative
window: 1 month
input_metric: order_total
- name: cumulative_order_total_mtd
label: "Cumulative order total (MTD)"
description: "The month-to-date value of all orders"
type: cumulative
grain_to_date: month
input_metric: order_totalWith period_agg for re-aggregation at non-default granularity:
metrics:
- name: cumulative_revenue
description: "The cumulative revenue for all orders."
label: "Cumulative revenue (all-time)"
type: cumulative
input_metric: revenue
period_agg: first # first | last | average. Defaults to first.window and grain_to_date cannot be used together.
Create a ratio between two metrics. Numerator and denominator can be strings (metric name) or dicts (with name, filter, alias).
metrics:
- name: food_order_pct
description: "The food order count as a ratio of the total order count"
label: Food order ratio
type: ratio
numerator: food_orders
denominator: ordersWith filter and alias:
metrics:
- name: frequent_purchaser_ratio
description: Fraction of active users who qualify as frequent purchasers
type: ratio
numerator:
name: distinct_purchasers
filter: |
{{ Dimension('customer__is_frequent_purchaser') }}
alias: frequent_purchasers
denominator:
name: distinct_purchasersMeasure how often one event leads to another for a specific entity within a time window.
metrics:
- name: visit_to_buy_conversion_rate_7d
description: "Conversion rate from visiting to transaction in 7 days"
type: conversion
label: Visit to buy conversion rate (7-day window)
entity: user
calculation: conversion_rate # conversion_rate (default) or conversions
base_metric:
name: visits
filter: "{{ Dimension('visits__referrer_id') }} = 'facebook'"
conversion_metric: buys
window: 7 daysWith constant properties (ensure same dimension value across base and conversion events):
metrics:
- name: view_item_detail_to_purchase_with_same_item
description: "Conversion rate for users who viewed and purchased the same item"
type: conversion
label: View item detail > Purchase
entity: user
calculation: conversions
base_metric: view_item_detail
conversion_metric: purchase
window: 1 week
constant_properties:
- base_property: product
conversion_property: productFor metrics depending on multiple semantic models, define them at the top-level metrics: key:
metrics:
- name: orders_per_session
type: ratio
numerator: orders
denominator: sessions
config:
group: example_group
tags:
- example_tag
meta:
owner: "@someone"For slowly changing dimension tables, use validity_params on time dimensions and natural entity type:
models:
- name: sales_person_tiers
semantic_model:
enabled: true
agg_time_dimension: tier_start
primary_entity: sales_person
columns:
- name: start_date
granularity: day
dimension:
type: time
name: tier_start
label: "Start date of tier"
validity_params:
is_start: true
- name: end_date
granularity: day
dimension:
type: time
name: tier_end
label: "End date of tier"
validity_params:
is_end: true
- name: tier
dimension:
type: categorical
name: tier
- name: sales_person_id
entity:
type: natural
name: sales_personSCD Type II semantic models cannot contain simple metrics.
semantic_model: block at model level with enabled: trueagg_time_dimension: at model level (not nested under semantic_model:)entity: and dimension: blocks on columns (a column can have one or the other, not both)granularity: required at column level for time dimensionsmetrics: array at model level for single-model metricsmetrics: key for cross-model metrics (derived, ratio, cumulative, conversion only)derived_semantics: for computed dimensions/entities not tied to a single column| Pitfall | Fix |
|---|---|
Missing agg_time_dimension | Every semantic model needs a default time dimension |
granularity inside dimension: block | Must be at column level, not nested under dimension: |
| Defining a column as both an entity and a dimension | A column can only be one or the other |
Simple metrics in top-level metrics: | Top-level is only for cross-model advanced metrics |
Using window and grain_to_date together | Cumulative metrics can only have one |
Missing input_metrics on derived metrics | Must list metrics used in expr |
Using type_params or measures | Those are legacy spec syntax; this spec uses direct keys |
evals
skills
adding-dbt-unit-test
references
answering-natural-language-questions-with-dbt
building-dbt-semantic-layer
configuring-dbt-mcp-server
fetching-dbt-docs
scripts
migrating-dbt-core-to-fusion
running-dbt-commands
troubleshooting-dbt-job-errors
using-dbt-for-analytics-engineering