> ## Documentation Index
> Fetch the complete documentation index at: https://lightdash-mintlify-4218de93.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# dbt MetricFlow metrics

> Connect Lightdash to your dbt MetricFlow semantic layer metrics

If your dbt project defines metrics using [MetricFlow](https://docs.getdbt.com/docs/build/about-metricflow) (dbt's semantic layer), the Lightdash CLI can translate them into Lightdash metrics automatically when you deploy. You keep a single source of truth for metric definitions in MetricFlow format, and Lightdash reads them directly from your compiled dbt project. You don't need a dbt Cloud subscription or the dbt Semantic Layer API, and you don't need to duplicate the definitions.

## How it works

When you run `lightdash deploy` (or `lightdash compile` / `lightdash preview`), the CLI reads your project's compiled `manifest.json`, which contains everything MetricFlow knows about your project: the `semantic_models` (entities, dimensions, measures) and the `metrics` defined on top of them.

These metrics can then be used everywhere Lightdash metrics work (charts, dashboards, the API, AI agents).

```bash theme={null}
dbt parse                # or dbt compile — writes target/manifest.json
lightdash deploy         # translates MetricFlow metrics as part of the deploy
```

### Requirements

* **dbt Core 1.6 or later** (manifest schema `v10`, the first version to include MetricFlow's semantic layer). The legacy metrics format used by pre-1.6 dbt (`calculation_method` / `expression` / `time_grains`) is no longer read.
* **The Lightdash CLI.** Translation happens in `lightdash compile`, `lightdash preview`, and `lightdash deploy`. Server-side jobs (scheduled runs from a connected Git repo) don't currently translate MetricFlow metrics — for now, deploy from the CLI.

<Info>
  If you define a metric with the same name in both MetricFlow and your model's `meta.metrics`, the `meta.metrics` (Lightdash YAML) definition will take precedence — so you can always override a translated metric by hand.
</Info>

### Use the latest MetricFlow spec

Lightdash supports the latest and legacy spec, though it's recommended to use the latest spec.

* **Legacy spec** (dbt Core 1.6+): top-level `semantic_models:` and `metrics:` blocks with `type_params`.
* [**Latest spec**](https://docs.getdbt.com/docs/build/latest-metrics-spec) (dbt Fusion engine, dbt platform, dbt Core 1.12+): `semantic_model:` enabled inline on the model, with entities/dimensions on columns and metrics using top-level `agg` / `expr` keys.

## Supported features

`simple` metrics, and measures flagged `create_metric: true`, translate into Lightdash:

| MetricFlow                                                   | Lightdash metric type                                                          |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------ |
| `agg: sum`                                                   | `sum`                                                                          |
| `agg: count`                                                 | `count`                                                                        |
| `agg: count_distinct`                                        | `count_distinct`                                                               |
| `agg: average`                                               | `average`                                                                      |
| `agg: median`                                                | `median`                                                                       |
| `agg: min` / `agg: max`                                      | `min` / `max`                                                                  |
| `agg: percentile`                                            | `percentile`                                                                   |
| `agg: sum_boolean`                                           | `sum` over `CASE WHEN <bool> THEN 1 ELSE 0 END`                                |
| Metric or measure `filter:` (same-model `Dimension()` refs)  | filter compiled into the metric SQL as `CASE WHEN <condition> THEN <expr> END` |
| `ratio` metrics (inputs on the same dbt model)               | `number` metric: `(${numerator} * 1.0) / NULLIF(${denominator}, 0)`            |
| `derived` metrics (inputs on the same dbt model, no offsets) | `number` metric with the `expr` rewritten over `${metric}` references          |

Also carried over:

* **Measure** `expr`: bare column references become the metric's SQL, qualified with `${TABLE}` (for example, `expr: amount` becomes `sql: ${TABLE}.amount`). Full SQL expressions are used verbatim.
* **Labels and descriptions**: from the metric, falling back to the measure's.
* **Percentile value**: MetricFlow's legacy spec authors percentile as a `0–1` fraction (`percentile: 0.95`) and the latest spec authors it as `0–100` (`percentile: 95`). Both are normalized to Lightdash's `0–100` scale automatically.
* **`config.meta.hidden` and `config.meta.group_label`**: read from the metric first, falling back to the measure. Use them to hide translated helper metrics from the explore sidebar or [group them](/references/metrics#groups) alongside your other Lightdash metrics. Unknown keys under `config.meta` are ignored.

### Notes on filters, ratio, and derived metrics

* **Filters** translate when every `{{ Dimension('entity__dim') }}` reference resolves on the metric's own semantic model. Cross-model dimension references, and other template functions (`TimeDimension()`, `Entity()`, `Metric()`), skip the metric with a warning.
* **Ratio and derived inputs** must all resolve to metrics on the same dbt model. In MetricFlow, inputs can come from any semantic model because each input is aggregated in its own subquery; Lightdash compiles a single query per explore, so cross-model inputs are skipped with a warning. Join the relevant models in a Lightdash explore and author a `number` metric by hand if you need that today.
* **Filtered inputs** to a ratio or derived metric (for example, a ratio whose numerator has its own `filter:`) compile the filter into a hidden helper metric that the visible metric references.
* **Time-offset inputs** to a derived metric (`offset_window` or `offset_to_grain`) are skipped with a warning.

## What's not supported yet

These are skipped with a warning on deploy (details under `--verbose`):

| MetricFlow feature                                               | Notes                                                                                                                        |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `cumulative` metrics                                             | require time-spine semantics                                                                                                 |
| `conversion` metrics                                             | require entity-journey semantics                                                                                             |
| Cross-model `ratio` / `derived` inputs                           | inputs must all resolve on the same dbt model — see the notes above                                                          |
| Derived-metric `offset_window` / `offset_to_grain`               | time-offset inputs aren't translated                                                                                         |
| `filter:` templates that aren't same-model `Dimension()` refs    | cross-model dimensions and `TimeDimension()` / `Entity()` / `Metric()` templates don't map to Lightdash metric filters       |
| `agg: percentile` without a numeric `percentile` value           | skipped rather than defaulted — set `type_params.measure.agg_params.percentile` (legacy) or `agg_params.percentile` (latest) |
| `percentile_type: discrete`                                      | Lightdash percentiles always compile to `PERCENTILE_CONT`                                                                    |
| `join_to_timespine`, `fill_nulls_with`, `non_additive_dimension` | no equivalents                                                                                                               |

Cumulative and conversion metric translation, cross-model ratio/derived inputs, and server-side translation from a connected Git repo are on the roadmap.

And these parts of the semantic model are currently skipped:

* **Entities / joins.** MetricFlow joins semantic models implicitly at query time through shared entity keys. Lightdash joins are explicit and authored per-explore ([joining tables](/references/joins)).
* **Dimensions and `agg_time_dimension`.** Lightdash generates dimensions from your model's real columns, so all of your columns are already available as dimensions, and metrics can be grouped by any of them — the MetricFlow dimension definitions aren't needed.

## Example

A complete working example (both specs, with a reproducible test) lives in the Lightdash repo under [`examples/metricflow-demo`](https://github.com/lightdash/lightdash/tree/main/examples/metricflow-demo). The short version, in the legacy spec:

```yaml theme={null}
semantic_models:
  - name: orders
    model: ref('orders')
    defaults:
      agg_time_dimension: ordered_at
    entities:
      - name: order
        type: primary
        expr: order_id
    dimensions:
      - name: ordered_at
        type: time
        type_params:
          time_granularity: day
      - name: status
        type: categorical
    measures:
      - name: total_revenue
        agg: sum
        expr: amount
      - name: order_count
        agg: count
        expr: order_id
      # create_metric: true auto-creates a metric — also translated
      - name: unique_customers
        agg: count_distinct
        expr: customer_id
        create_metric: true

metrics:
  - name: total_revenue
    label: Total revenue
    type: simple
    type_params:
      measure: total_revenue
    # config.meta carries over to the translated Lightdash metric
    config:
      meta:
        group_label: Order metrics
  # Same-model filter → CASE WHEN in the metric SQL
  - name: completed_revenue
    label: Completed revenue
    type: simple
    type_params:
      measure: total_revenue
    filter: |
      {{ Dimension('order__status') }} = 'completed'
  # Same-model ratio → Lightdash `number` metric
  - name: revenue_per_order
    label: Revenue per order
    type: ratio
    type_params:
      numerator: total_revenue
      denominator: order_count
```

Deploying this project produces four metrics on the `orders` explore: `total_revenue` (`sum` on `${TABLE}.amount`, grouped under "Order metrics"), `unique_customers` (`count_distinct` on `${TABLE}.customer_id`, from the `create_metric: true` measure), `completed_revenue` (a `sum` over `CASE WHEN ${TABLE}.status = 'completed' THEN ${TABLE}.amount END`), and `revenue_per_order` (a `number` metric of `(${total_revenue} * 1.0) / NULLIF(${order_count}, 0)`) — all with no Lightdash-specific YAML.
