In the legacy format, semantic models were top-level resources, and dbt’s best-practice guide suggested
a parallel folder of sem_*.yml files. The latest YAML spec changes the constraint: the semantic model
is part of the model’s own YAML entry, and dbt allows only one entry per model. The layout follows from
that.
Copy and paste
models/
marts/
orders.sql
orders.yml # columns, tests, entities, dimensions, metrics of orders
customers.sql
customers.yml
metrics/
company_kpis.yml # metrics that combine several semantic models
saved_queries/
finance.yml # saved queries and their exports
utilities/
time_spine_daily.sql
time_spine_daily.yml # time_spine: config and custom granularities
A cross-model metric in its own file:
# models/metrics/company_kpis.yml
metrics:
- name: revenue_per_signup
label: Revenue per signup
type: ratio
numerator: revenue # defined on orders
denominator: signups # defined on customers
One entry per model
Entities, dimensions and single-model metrics sit under the model, next to its column descriptions and
tests. Describing orders in a second file, for example to keep the semantic part apart, stops the
parse:
Compilation Error
dbt found two schema.yml entries for the same resource named orders. Resources and their associated
columns may only be described a single time. To fix this, remove the resource entry for orders in one
of these files:
- models/semantic/sem_orders_docs.yml
models/_semantic.yml
So the old sem_orders.yml pattern no longer works for semantic models. Keep one YAML file per mart, as
in the layout above, and let it grow: a mart’s documentation, tests and semantics are reviewed together.
What can live elsewhere
- Metrics that use more than one semantic model: a ratio of revenue (orders) to signups (customers),
or a derived metric over both. They must go under a top-level
metrics:key, which can be in any YAML file. Ametrics/folder grouped by business area makes them easy to find. - Saved queries and exports, which usually belong to a team or a dashboard rather than to a model.
- The time spine with its custom granularities, such as a fiscal calendar.
Single-model metrics that only use one semantic model can stay under the model’s metrics: list.
Inside model-paths
Every file must sit under a folder listed in model-paths (usually models/). dbt’s guide warns that
YAML outside it produces an empty semantic_manifest.json: no error, just no metrics.
Naming
- Metric names are global. A second metric called
revenue, even on another model, stops the parse with “change the name of one of these resources”. Names such asgross_revenueandnet_revenuebeat a genericrevenuein a large project. Give every metric alabelfor the BI tools. - Entity names are join keys. Use the same singular noun,
customer, wherever a column refers to customers; that shared name is what lets MetricFlow join two models. - Dimension names only need to be unique within a semantic model; queries address them through
their entity, as
customer__country.
Check the structure
dbt parse
mf validate-configs # or, with dbt platform: dbt sl validate
mf list metrics
mf list metrics (or dbt sl list metrics) shows every metric the parse found, which is the quickest way
to spot a file that was not picked up.
Tested with dbt Core 1.12 and MetricFlow 0.213 on DuckDB.