dbt Core logodbt Core integration

Your dbt Core semantic layer defines the metric. KPI Tree explains the movement, names the owner and proves the fix.

Upload the semantic manifest your dbt Core project already compiles.

Governed in dbt Core. Explained in KPI Tree. One manifest, the whole loop.

A dbt Core project is the cleanest definition of a metric a business can have: version-controlled YAML, one calculation, reviewed in a pull request. KPI Tree treats it as the source of truth. It reads semantic_manifest.json straight from your target directory, renders the SQL with an in-process MetricFlow engine, and runs it on the warehouse your models build into. Nothing is re-declared, re-mapped or copied into a second semantic layer, and no dbt Cloud API sits in the path. No other dbt Semantic Layer integration on dbt's own list reads a dbt Core manifest directly.

What the dbt Semantic Layer does not know is why Revenue fell, who owns Conversion, or whether Monday's release moved it. That is the layer KPI Tree adds: a causal metric tree re-tested every night, RACI ownership on every node, action plans measured against a forecast, and Canopy, the business context layer that hands all of it to your people and to the agents they already use over MCP. Your dbt project stays the single source of truth for how a metric is calculated. KPI Tree becomes the source of truth for what to do about it.

Every definition, as written, nothing re-declared

Metrics, dimensions, entities, measures, labels and descriptions come across intact. Sum, average, first and last are read from the definition, so weekly and monthly rollups behave the way your YAML says.

Choose metrics to sync

4 of 5 selected

Revenue

dimensions: region, channel

sum

Orders

dimensions: region, channel, plan

count

Average order value

dimensions: region

ratio

Active customers

dimensions: plan

count distinct

Cumulative bookings

dimensions: none

cumulative

Aggregation read from each definition. Nothing re-declared.

One query per metric, everything else in memory

Each metric is one aggregation query at day grain. Comparisons, rollups, breakdowns and the nightly correlation and causality sweep run in KPI Tree’s own engine, so the warehouse bill stays flat as the tree grows.

Warehouse queries · last sync

4 total
Revenue1 query · 1.8s · 412 rows
Orders1 query · 1.2s · 412 rows
Average order value1 query · 1.6s · 412 rows
Active customers1 query · 2.3s · 412 rows

0 warehouse queries for

period comparisons, weekly and monthly rollups, dimension breakdowns, nightly correlation and causality tests. All computed in memory from those four results.

Dimension metrics, created automatically

Switch on Create Dimension Metrics and every dimension you chose becomes a child metric per value: Revenue (Region: EMEA), Revenue (Region: APAC), and so on. Each child gets its own owner, baseline and nightly driver tests, so you see which region moved and who owns it. No YAML changes.

Revenue

Create Dimension Metrics · on

dimensions: region, channel · 5 child metrics created

Revenue (Region: EMEA)£612k4%
Revenue (Region: APAC)£318k21%
Revenue (Region: UK)£350k2%
Revenue (Channel: Web)£880k1%
Revenue (Channel: App)£400k9%

Each child has its own owner, baseline and nightly driver tests. No YAML changes.

Re-sync as a diff, trees and owners untouched

Every upload is compared with the last. New metrics appear, changed ones update in place, removed ones retire with their history kept. Ownership, trees and action history stay exactly where you left them.

Sync summary

Completed 06:14

42

Found

3

Created

38

Updated

1

Archived

0

Skipped

Dimension metrics created118

customer__customer_id skipped: 48,211 values, above the 50 value limit

Trees, owners and action history preserved · gross_margin renamed in place

Connected in three steps. The manifest you already build, the warehouse you already run.

A dbt Core connection holds definitions and never executes anything itself. Link the warehouse the models build into, upload the manifest, and the first sync of your dbt Semantic Layer starts on its own.

Link the warehouse the models build into

Choose an existing Snowflake, BigQuery, Databricks, Redshift or PostgreSQL connection that points at the database and schema your dbt models materialise in. KPI Tree renders each metric in that dialect and runs it there with read-only credentials.
  • Snowflake, BigQuery, Databricks, Redshift and PostgreSQL
  • Read-only, scoped credentials, encrypted at rest
  • No dbt CLI, adapter or profile needed on our side

dbt Core Semantic Layer

Connected
Execution connectionanalytics_prod · marts
Manifesttarget/semantic_manifest.json
Last uploadGitHub Actions · main · 06:12
Runs against
SnowflakeBigQueryDatabricksRedshiftPostgreSQL

Upload the semantic manifest

Run dbt parse or dbt build and upload target/semantic_manifest.json, or a ZIP of the whole target directory to bring manifest.json, catalog.json, run_results.json and sources.json with it. The sync starts as soon as the file lands.
  • dbt Core 1.6 onwards: the measures-based spec and the modernised spec are both read
  • Up to 50 MB per artifact or ZIP
  • Sync runs automatically on every upload
zsh

~/analytics % dbt build

Running with dbt=1.12

Found 84 models, 12 sources, 41 metrics, 9 semantic models

Completed successfully. Artifacts written to target/

~/analytics % cd target && zip dbt_artifacts.zip semantic_manifest.json manifest.json run_results.json sources.json catalog.json

adding: semantic_manifest.json (deflated 91%) ... catalog.json (deflated 88%)

~/analytics % curl -X POST -H "Authorization: Bearer $KPITREE_API_KEY" -F "artifacts=@target/dbt_artifacts.zip" "https://acme.kpitree.co/api/connections/$KPITREE_CONNECTION_ID/semantic_layer/dbt/artifacts"

202 Accepted · sync started · 41 metrics found

Keep it in sync from CI

The wizard writes a GitHub Actions workflow for you. On every push to main it runs dbt build, zips the target directory and posts it to the connection with one scoped API key. curl and a Python script cover any other pipeline.
  • One repository secret: an API key scoped to semantic layer uploads
  • Workspace domain and connection ID travel as workflow variables
  • Swap the adapter line for your own warehouse
.github/workflows/dbt-kpitree.ymlgenerated by the wizard

name: dbt Build and Sync to KPI Tree

on:

push:

branches: [main]

env:

KPITREE_DOMAIN: acme.kpitree.co

KPITREE_CONNECTION_ID: 9f2c…c41a

jobs:

dbt-build:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- run: pip install dbt-core dbt-snowflake

- run: dbt deps && dbt build

- name: Upload artifacts to KPI Tree

run: |

zip -j target/dbt_artifacts.zip target/*.json

curl -X POST -H "Authorization: Bearer ${{ secrets.KPITREE_API_KEY }}" \

-F "artifacts=@target/dbt_artifacts.zip" \

"https://${{ env.KPITREE_DOMAIN }}/api/connections/${{ env.KPITREE_CONNECTION_ID }}/semantic_layer/dbt/artifacts"

What comes across from a dbt Core semantic layer. And what stays exactly where it is.

The semantic manifest carries everything KPI Tree needs to render a dbt Semantic Layer metric. The optional artifacts add the context that explains a change. Nothing is written back to your project.

Metrics simple, ratio, cumulative, derived, conversion

Every dbt Semantic Layer metric with a day-level time dimension, with its label, description, type and filters. Metrics defined only at coarser grains are reported as skipped rather than guessed at, and a conversion metric can carry a declared rollup so nothing is assumed.

Dimensions and entities child metrics created for you

Pick the dimensions that matter for each metric. KPI Tree probes their distinct values on your warehouse and creates a child metric per value automatically, within a cardinality limit you set by connection, by dimension or by metric. Entities come across too, so an assistant can follow the joins.

Aggregation and rollups read, inferred, or declared

Sum, count, average, min and max map straight from the measure. Stocks and flows are inferred from the metric type and any non-additive dimension, and you can pin the answer in your YAML with meta.kpi_tree.aggregation so the derivation never second-guesses it.

Five artifacts, one ZIP. The context behind every number.

Include the rest of the target directory and every metric gains its own lineage, column context, build history and freshness. An assistant can then check whether a movement is a business change or a stale source before anyone acts on it.

semantic_manifest.json

Metric definitions

required

Metrics, semantic models, measures, dimensions and entities. Starts the sync.

manifest.json

Model lineage

optional

Models, seeds and sources with their dependencies. Unlocks data model exploration in the app and over MCP.

catalog.json

Column context

optional

Every warehouse column with its real data type, merged over the descriptions you wrote.

run_results.json

Build history

optional

Last build status and timing on every model, and each metric’s refresh cadence worked out from your run history.

sources.json

Source freshness

optional

Freshness status and loaded-at times, so stale upstream data shows on the metric itself.

Artifacts arrive through the upload endpoint from your own pipeline, up to 50 MB each. Tests and exposures are not read, and lineage is kept at model level.

Ask an agent the same question twice. Once on the dbt Semantic Layer, once on Canopy above it.

A dbt Core team usually already has an agent on the warehouse, or MetricFlow running locally, and it comes back with a governed number. The fair question is what Canopy adds. The pair below shows the shape of the difference, and the benchmark beneath it measures it on eight real business questions.

The semantic layer alone

A correct number, and a dead end.

Every consumer of the dbt Semantic Layer, dbt’s own MCP server included, gets the same governed figure. None of them gets the cause, the owner or the follow-up, so the question goes back to the data team.

Why is revenue down this month?
Revenue is £1.28m month to date, 15% below last month. The metric is defined as the sum of order_total where status is complete.
I do not have information about what caused the change or who is responsible. Would you like me to break it down by region?

Canopy on top of dbt

The driver, the owner, the build check and the next step.

Canopy reads the causal tree, the RACI, the build history from your dbt artifacts and the open tasks, so the first answer is the one people act on.

Why is revenue down this month?
Conversion rate is the driver, down 23%, Granger-causal at a three day lag. Traffic and order value are flat. The drop starts the day after Monday's checkout release.
The data is sound: fct_orders built at 06:12 and every source passed freshness. Sarah Chen is Accountable and a rollback task is already open. Shall I attach this analysis to it?
driver · q < 0.05owner · Sarah Chenbuild · freshtask · open

Part of the dbt Semantic Layer integration. One connection for dbt Core, one for dbt Cloud, the same layer above.

The hub page covers what the dbt Semantic Layer is, what KPI Tree adds above it, the benchmark and the security posture. The dbt Cloud page covers the Semantic Layer API path with a service token.

Common questions

Do I need a dbt Cloud account?

No. KPI Tree reads semantic_manifest.json from your dbt Core project and renders the metric SQL itself with an in-process MetricFlow engine, so there is no dbt Cloud account, Semantic Layer API or service token in the path. If you later move to dbt Cloud, the dbt Cloud integration connects through the Semantic Layer API instead.

Which versions of dbt Core and which YAML spec are supported?

dbt Core 1.6 onwards, which is when MetricFlow and the semantic manifest arrived. KPI Tree reads both manifest shapes: the measures-based spec from dbt Core 1.6 to 1.11 and the modernised spec from 1.12 onwards, where simple metrics replace measures. The manifest is what MetricFlow itself reads, so the connection follows your project through the spec migration.

Where does the metric SQL run?

On your own warehouse. A dbt Core connection holds definitions and never executes anything itself. KPI Tree renders each metric as MetricFlow SQL in the dialect of the linked warehouse and runs one aggregation query per metric at day grain. Period comparisons, weekly and monthly rollups, dimension breakdowns and the nightly correlation and causality tests are all computed in KPI Tree’s own in-memory engine from those results.

Which warehouses can a dbt Core connection run on?

Snowflake, BigQuery, Databricks, Redshift and PostgreSQL. The linked connection should point at the database and schema your dbt models build into. Azure SQL and Google Sheets connections cannot be linked to a dbt Core connection.

How do I upload the manifest and keep it current?

Four ways, shown as tabs in the connection wizard: upload the file or a ZIP of the target directory in the browser, post it with curl, run the Python script the wizard provides, or commit the GitHub Actions workflow it generates. The workflow runs dbt build on every push to main and posts the artifacts with an API key scoped to semantic layer uploads. Every upload starts a sync automatically. Artifacts and ZIPs can be up to 50 MB each.

What happens when my dbt project changes?

Each upload is compared with the previous one and the sync report lists what was created, updated, retired and skipped. New metrics appear, edited definitions update in place, and metrics removed from the project or deselected for sync are retired rather than deleted, with their history and recorded context kept. Trees, ownership and action history are preserved. A metric whose name changes in dbt is treated as a new metric.

Which metric types come across?

Simple, ratio, cumulative, derived and conversion metrics, as long as the metric can be queried at day grain. Metrics defined only at weekly or coarser grains are listed as skipped in the sync report rather than guessed at. Every other grain, from week to quarter, is computed by KPI Tree from the daily series.

How does KPI Tree decide whether to sum or take the last value across a week or a month?

It reads the aggregation from the definition first: sum, count, average, min and max map straight from the measure, a ratio or cumulative metric rolls up as its last value, and a non-additive dimension marks a stock that takes its first or last value. Where the definition leaves it open, the metric type and name decide, and the sync report says which rollups were declared and which were inferred. To settle it yourself, add meta.kpi_tree.aggregation to the metric or measure in your YAML and the derivation never overrides it.

Can I choose which metrics and dimensions to sync?

Yes. The Metrics tab lists every metric in the manifest and you choose the dimensions for each one. KPI Tree probes the distinct values of a chosen dimension on your warehouse and creates a child metric per value, so Revenue with a Region dimension gains a node for each region with its own owner and tracking. The default limit is 15 values per dimension, adjustable between 2 and 200 at connection, dimension or metric level, and any dimension above its limit is skipped with the reason shown in the sync report.

What do manifest.json, catalog.json, run_results.json and sources.json add?

manifest.json brings model lineage, so every metric can be traced to the models and sources that produce it, in the app and over MCP. catalog.json adds every warehouse column with its real data type. run_results.json records each model’s last build status and timing and works out how often each metric’s data refreshes. sources.json adds source freshness, so a metric whose upstream source has gone stale says so on the metric itself. Only semantic_manifest.json is required.

Are saved queries, exports, tests or exposures read?

Not at present. KPI Tree syncs the metrics themselves and you choose dimensions per metric, so saved queries are not imported. Exports land as tables in your warehouse, and an export table can be tracked as a SQL metric on the warehouse connection. dbt tests and exposures are not read, and lineage is kept at model level rather than column level.

Does KPI Tree write to my dbt project or my warehouse?

No. The connection reads a manifest and runs SELECT statements with scoped, read-only credentials. Nothing is written back to the project, no jobs are triggered and no models are touched.

Is this the dbt metrics layer?

The dbt Semantic Layer is the successor to the dbt metrics layer. It keeps the idea of metrics defined once in YAML and adds semantic models, entities and MetricFlow, which compiles the SQL. KPI Tree reads the semantic manifest MetricFlow produces, so it works with the current spec rather than the retired metrics package.

Can I combine several dbt projects on one tree?

Yes. Each dbt project is its own connection with its own manifest, and metrics from several projects sit on the same tree with their own calculation sources. The tree carries the drivers, owners, targets and actions across them.

Can dbt metrics share a tree with metrics from other sources?

Yes. Metrics from several dbt projects, from Snowflake Semantic Views or Databricks Unity Catalog, from SQL on a warehouse connection and from spreadsheets all sit on the same tree. Each keeps its own calculation source while the tree carries the drivers, owners, targets and actions across them.

How do AI agents use the dbt connection?

Through Canopy, KPI Tree’s business context layer, over MCP. An assistant such as Claude, ChatGPT, Gemini or Copilot can analyse a metric with its drivers, owners and recorded context, explore the dbt data model behind it, see the last build and source freshness, and, with editor access, run read-only queries on the linked warehouse to test an explanation.

Should I use this or the dbt Cloud integration?

Use this one if you run dbt Core without dbt Cloud, or if you want the SQL to run on your own warehouse with no dbt Cloud usage. If you have a dbt platform plan with the Semantic Layer, the dbt Cloud integration reads your catalogue live through the Semantic Layer API with no uploads.

You governed the definition. Now govern the decision.

Connect your dbt Core project and see your own metrics as a causal tree with named owners and verified actions, in a demo on your data.

The guide

dbt semantic layer and metric trees: how the two layers fit together, and where each one stops.

Read the guide

Experience That Matters

Built by a team that's been in your shoes

Our team brings deep experience from leading Data, Growth and People teams at some of the fastest growing scaleups in Europe through to IPO and beyond. We've faced the same challenges you're facing now.

Checkout.com
Planet
UK Government
Travelex
BT
Sainsbury's
Goldman Sachs
Dojo
Redpin
Farfetch
Just Eat for Business