Skip to main content
Availability: MetricFlow support is a Beta feature. Behavior and supported features may change as we iterate.
If your dbt project defines metrics using MetricFlow (dbt’s semantic layer), Lightdash can translate them into Lightdash metrics automatically. You keep a single source of truth for metric definitions in MetricFlow format, and Lightdash reads them directly from your dbt project — you don’t need to duplicate the definitions. This works with every way of connecting a dbt project:
  • Lightdash CLI (lightdash deploy / compile / preview) — reads your compiled manifest.json. No dbt Cloud subscription or dbt Semantic Layer API needed.
  • Git connections (GitHub, GitLab, Azure DevOps, Bitbucket) — the same translation runs when Lightdash compiles your project server-side.
  • dbt Cloud connection — Lightdash pulls your semantic models and metrics from the dbt Cloud Discovery API when you refresh the project. See Using the dbt Cloud connection for details and limitations.

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. Projects connected via git are compiled the same way server-side when you refresh dbt in Lightdash. These metrics can then be used everywhere Lightdash metrics work (charts, dashboards, the API, AI agents).
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.

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 (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: Also carried over:
  • Measure expr: bare column references and SQL expressions both become the metric’s SQL.
  • Labels and descriptions: from the metric, falling back to the measure’s.

Filters

Metric-level and measure-level filter: templates translate when every reference is a {{ Dimension('entity__dimension') }} that resolves on the metric’s own semantic model. The filter is compiled into the metric SQL:
becomes a Lightdash sum metric with SQL CASE WHEN ("orders".status = 'completed') THEN ("orders".amount) END. The dimension’s expr is used when it isn’t a plain column. Filters referencing dimensions on other semantic models, or using other template functions (TimeDimension(), Entity(), Metric()), are skipped with a warning.

Ratio metrics

ratio metrics translate to a non-aggregate Lightdash number metric dividing the two input metrics, when the numerator and denominator both live on the same model:
becomes (${total_revenue} * 1.0) / NULLIF(${order_count}, 0) — the * 1.0 avoids integer division on warehouses that truncate, and NULLIF avoids division-by-zero errors. Filtered inputs work too: a numerator with its own filter: (e.g. completion rate = completed orders ÷ all orders) compiles the filter into a hidden helper metric that the visible ratio references. A ratio-level filter: applies to both inputs.

Derived metrics

derived metrics translate to a number metric with the expression rewritten over the input metrics (aliases supported), again when all inputs live on the same model:
becomes ${total_revenue} / ${unique_customers}. Inputs using offset_window or offset_to_grain (time-shifted metrics) are skipped with a warning.
Why same-model only? MetricFlow computes each input metric in its own aggregation subquery — even across unrelated tables — and joins the already-aggregated results. Lightdash compiles one query per explore, so ratio/derived metrics translate faithfully only when all inputs resolve to metrics on the same dbt model. Cross-model inputs are skipped with a warning naming the models involved.

Using the dbt Cloud connection

Projects connected through the dbt Cloud connection type don’t have a local manifest.json — instead, Lightdash fetches your semantic models and metrics from the dbt Cloud Discovery API alongside your models when you refresh the project. Translation then works exactly as described above, with no extra setup:
  • Your service token’s existing ‘Metadata Only’ permission covers the semantic layer queries — no dbt Semantic Layer configuration is required.
  • Definitions come from the environment’s latest successful run, like the rest of your dbt Cloud metadata: run a job that parses your project (any dbt build / dbt run job) and refresh dbt in Lightdash.
The Discovery API doesn’t expose every field that’s in the manifest, so a few things behave differently compared to the CLI or git connections:
  • Percentile measures are skipped (with a warning) — the API doesn’t return agg_params.percentile, and translating without the percentile value would silently compute a median.
  • Measure-level label and config.meta (e.g. hidden or group_label set on a measure) aren’t available. Set these on the metric instead of the measure — metric-level values come through fine.
  • Dimension expr isn’t available, so metric filter: references resolve against the dimension name. If a filtered dimension’s name doesn’t match a real column on your model, define the filter on the metric in Lightdash YAML instead.

What’s not supported yet

These are skipped with a warning on deploy (details under --verbose): 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).
  • 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. (Dimension expr is honored when resolving filter references.)

Example

A complete working example (both specs, with a reproducible test) lives in the Lightdash repo under examples/metricflow-demo — it exercises every supported shape, including filtered, ratio, derived, and sum_boolean metrics. The short version, in the legacy spec:
Deploying this project gives the orders explore two metrics, Total revenue (SUM("orders".amount)) and unique_customers (COUNT(DISTINCT "orders".customer_id)), with no Lightdash-specific YAML.