In the legacy format, a measure aggregated a column and a metric pointed at the measure. The latest YAML spec removes the middle step: a type: simple metric carries the aggregation itself, with agg and expr. “Measures” in this section means exactly that.

Copy and paste

    metrics:
      - name: revenue
        type: simple
        agg: sum
        expr: amount
      - name: order_count
        type: simple
        agg: count
        expr: 1                    # one per row
      - name: ordering_customers
        type: simple
        agg: count_distinct
        expr: customer_id
      - name: average_order_amount
        type: simple
        agg: average               # not avg
        expr: amount
      - name: smallest_order
        type: simple
        agg: min
        expr: amount
      - name: largest_order
        type: simple
        agg: max
        expr: amount
      - name: median_order
        type: simple
        agg: median
        expr: amount
mf query --metrics order_count,ordering_customers,revenue,average_order_amount,smallest_order,largest_order,median_order \
  --group-by metric_time__year
Year order_count ordering_customers revenue average_order_amount smallest_order largest_order median_order
2025 12 4 1,340 111.67 60 200 105
2026 7 5 890 127.14 50 300 110

The aggregations

agg Returns Adds up across groups?
sum total of expr yes
count number of non-null values of expr; expr: 1 counts rows yes
count_distinct number of different values no
average mean of expr no
min, max smallest, largest value no (but min of mins works)
median middle value no
percentile see percentile measures no
sum_boolean number of rows where a boolean expr is true yes

The keyword is average: agg: avg stops the parse with Invalid enum value: `avg` in enum AggregationType. expr defaults to the metric’s name, so a metric called amount with agg: sum would sum the amount column; writing expr explicitly is clearer.

Non-additive measures are computed, not summed

The Semantic Layer computes each metric from the rows at the grain you query, so non-additive measures stay correct: 2025 has 4 ordering customers and 2026 has 5, but over both years there are 5, not 9, because four of them ordered in both years. The same holds for averages and medians. What is not safe is adding up such values afterwards, in a spreadsheet or a BI total row.

expr is SQL

expr can be any expression on the model’s columns, evaluated row by row before the aggregation: amount - discount, case when ... end, a boolean for sum_boolean. It is pasted into the generated SQL, so write it in your warehouse’s dialect. For metrics that count only some rows, see how to count rows that match a condition.

Ratios are not measures

“Average order value” can be an average of amount, and here it is the same number, but as a ratio metric of revenue over orders it can also combine metrics with different filters or from different models. Use average for a plain mean of a column, and a ratio when the numerator and the denominator are business metrics of their own.

Tested with dbt Core 1.12 and MetricFlow 0.213 on DuckDB.

References