Migrate from dbt Semantic Layer
Convert your dbt semantic models and MetricFlow metrics into governed Malloy semantic models
The dbt Semantic Layer already expresses your business in entities, dimensions, measures, and metrics — which maps unusually cleanly onto Malloy. Credible reads your MetricFlow definitions, flattens the measure/metric split into Malloy measures, and — where you connect it — validates each metric against the Semantic Layer's own query engine.
What Credible Reads
Your semantic models (semantic_models: YAML — entities, dimensions, measures) and metrics (metrics: YAML — simple, ratio, derived, cumulative). The agent parses that project YAML directly — the fullest-fidelity input, since the YAML carries expr, filter, and agg_time_dimension details the compiled APIs abstract away. Connecting the official dbt MCP server (get_metrics, get_dimensions, get_entities, execute_sql) or the Semantic Layer APIs (GraphQL / JDBC / Python) is optional and adds live metric validation.
What Comes Across
The everyday modeling carries over. Here's how the bigger pieces land — and where they get better:
| In dbt | In Credible |
|---|---|
| Semantic models (entities, dimensions, measures) | Malloy sources, joins, dimensions, and measures |
| Metrics (simple / ratio / derived) | Measures — no separate measure-vs-metric layer to maintain |
Cumulative metrics & metric_time | Rebuilt as window views over explicit date fields |
| Metric descriptions | #(doc) / #(index), indexed by the AI Analytics Engine |
| Governance (none field-level today) | Fine-grained access control in the model, versioned and enforced everywhere |
| Semantic Layer API consumers | Directly queryable on every surface — agents over MCP, data apps, notebooks, dashboards, APIs |
The Migration Flow
Credible reads the semantic models and metrics, translates entities to keys/joins and measures/metrics to Malloy measures, enriches with #(doc)/#(index) tags, and — where you connect it — validates by querying each metric through the Semantic Layer API at the same grain and diffing the results — MetricFlow owns SQL generation, so its result is the canonical number to match.
What Credible Handles
- The measure/metric split flattens into one set of Malloy measures. A
simplemetric is often just a rename of its measure — Credible won't create two Malloy fields where one belongs. metric_timeand the time spine have no Malloy equivalent. Credible chooses the concrete date field per view and truncates with.month/.day; cumulative metrics are rebuilt as view-level window calculations.- Derived and ratio metrics reference other metrics, not columns. Credible resolves the dependency chain (metric → metric → measure → column) before writing the Malloy expression.
Before & After
dbt semantic model and metrics:
semantic_models:
- name: orders
model: ref('fct_orders')
defaults:
agg_time_dimension: order_date
entities:
- name: order_id
type: primary
- name: customer
type: foreign
expr: customer_id
dimensions:
- name: order_date
type: time
type_params: { time_granularity: day }
- name: status
type: categorical
expr: order_status
measures:
- name: order_total
description: Sum of order amounts
agg: sum
expr: amount
metrics:
- name: revenue
type: simple
type_params: { measure: order_total }
- name: completed_revenue
type: simple
type_params: { measure: order_total }
filter: "{{ Dimension('order__status') }} = 'completed'"
- name: completion_rate
type: ratio
type_params: { numerator: completed_revenue, denominator: revenue }source: orders is conn.table('analytics.fct_orders') extend {
primary_key: order_id
join_one: customers is conn.table('analytics.dim_customers') on customer_id
dimension:
#(doc) Order status
#(index)
status is order_status
measure:
#(doc) Total revenue (USD)
# currency
revenue is sum(amount)
#(doc) Number of orders
order_count is count(order_id)
#(doc) Revenue from completed orders
# currency
completed_revenue is sum(amount) { where: status = 'completed' }
#(doc) Share of revenue from completed orders
# percent
completion_rate is completed_revenue / revenue
view:
#(doc) Revenue by month
revenue_by_month is {
group_by: order_date.month
aggregate: revenue
}
}The two simple metrics collapse into their measures rather than duplicating them; completion_rate becomes a straight ratio; and the Jinja filter becomes a { where: … } on the measure.
More than a reformat. Your metrics become directly queryable and composable — not just a metrics API — AI-discoverable through the AI Analytics Engine, and deliverable to every surface. See what you gain →