Learn by Directing AI
All materials

metricflow-guide.md

MetricFlow Configuration Guide

What MetricFlow does

MetricFlow is a semantic layer framework for dbt that defines metrics once so every consumer gets the same calculation. When you define "revenue" in MetricFlow, every dashboard, ad hoc query, and downstream model that queries "revenue" uses the same formula. The definition is a contract -- it eliminates the "which revenue?" problem where different reports calculate the same metric differently.

Metric types

Simple metrics calculate a single aggregation over a measure. Revenue as the sum of order amounts. Average order value as the mean of order amounts. These are the building blocks.

Derived metrics combine other metrics with arithmetic. Profit margin as (revenue - cost) / revenue. Derived metrics reference other metric definitions, not raw columns -- if the underlying metric definition changes, the derived metric updates automatically.

Cumulative metrics aggregate over a rolling or unbounded time window. Year-to-date revenue. 30-day rolling average. These metrics require a time dimension and a grain specification.

Defining a metric

Metrics are defined in your schema.yml file alongside your dbt models. Here is an annotated example:

semantic_models:
  - name: orders
    defaults:
      agg_time_dimension: order_date
    model: ref('fct_orders')
    entities:
      - name: order_id
        type: primary
      - name: customer_id
        type: foreign
    dimensions:
      - name: order_date
        type: time
        type_params:
          time_granularity: day
      - name: order_status
        type: categorical
    measures:
      - name: order_total
        agg: sum
        expr: order_amount
      - name: order_count
        agg: count
        expr: order_id

metrics:
  - name: revenue
    description: "Total revenue from completed orders"
    type: simple
    type_params:
      measure: order_total
    filter:
      - "{{ Dimension('order_status') }} = 'completed'"
  - name: average_order_value
    description: "Average value per completed order"
    type: derived
    type_params:
      expr: revenue / order_count
      metrics:
        - name: revenue
        - name: order_count

Key elements:

  • Semantic model defines the source table, its entities (keys), dimensions (grouping columns), and measures (aggregatable columns)
  • Metrics reference measures and apply filters, creating a single authoritative calculation
  • Filters are applied at the metric level, not the query level -- every consumer gets the filtered result

Querying metrics

Once defined, metrics are queried via the mf query command or through the dbt Semantic Layer API:

mf query --metrics revenue --group-by order_date__month

This returns the metric value grouped by month, using the definition you specified. The formula, the filter, the aggregation -- all locked in. The consumer specifies what to group by and what time range to query, but never redefines how the metric is calculated.

Verification

After defining a metric:

  1. Query the metric via mf query for a specific time period and grouping
  2. Calculate the same value by hand from the raw data using SQL -- apply the same formula, the same filters, the same grain
  3. Compare the results -- they should match exactly. If they don't, the metric definition encodes a different calculation than you intended

This verification step is critical. A metric definition that compiles and returns a number is not the same as a metric definition that returns the right number. The formula must match the business intent, not just pass syntax validation.

Common pitfalls

  • Formula that compiles but calculates wrong. The metric definition is valid YAML, the query returns a number, but the number doesn't match what the business means. This happens when filters exclude or include the wrong records, or when the aggregation type is wrong (sum vs count, mean vs median).
  • Missing filters that change the denominator. An "average order value" that doesn't filter out cancelled orders includes zeros in the denominator, producing a lower average than the business expects.
  • Name collisions with existing metrics. If two metrics have the same name but different calculations, one silently overrides the other. Always check that a metric name doesn't already exist before defining it.
  • Time grain mismatches. A metric defined at daily grain queried at monthly grain may produce unexpected results if the aggregation doesn't compose correctly (e.g., averaging daily averages is not the same as the monthly average).
  • Derived metrics referencing stale components. If a derived metric references another metric that was redefined, the derived metric's behavior changes without any direct edit to its definition.