Guides
How to build a metrics layer
Define each metric once, in code, so every tool that queries revenue or churn gets the same number — and govern changes to it.
Ask three people in most companies how "active user" is defined and you will get three different SQL queries, each defensible, each producing a different number. A metrics layer — sometimes called a semantic layer — exists to close that gap: it defines a metric once, in one place, as code, and every dashboard, spreadsheet connection and AI assistant that asks for "active users" gets the same computation. This guide is about the practice of building and governing that layer, not about any one vendor's implementation of it.
What a metrics layer actually is
At minimum, a metric definition specifies three things: the measure (a sum, count or ratio), the grain it is computed at (per day, per customer, per order), and the filters that decide what counts (completed orders only, excluding refunds, excluding internal test accounts). Write that once, and every consumer — a BI tool, a spreadsheet plug-in, a reverse ETL sync, a large language model generating SQL against your warehouse — reads from the same definition instead of reimplementing it.
This differs from a plain dashboard built on a query: a dashboard shows one view of a metric; a metrics layer is the reusable definition that any number of dashboards, in any number of tools, can draw from.
Where the layer lives
Three places compete for this role, and the right one depends on how many tools query your data:
- Inside one BI tool's model. Looker's LookML is the clearest example: definitions live centrally, but only tools that speak LookML can use them. Fine if one BI tool is genuinely the only consumer.
- In the transformation layer, as code. dbt's metrics and semantic-model features let you define a metric next to the SQL models that build it, version-controlled, tested, and queryable by any tool that can hit the warehouse through dbt's semantic layer interface.
- In a standalone, headless semantic layer. Cube and similar products sit between the warehouse and every consumer, exposing the same metric over SQL, REST and GraphQL, so no single BI tool owns the definition. This is the right choice once you run more than one BI tool, or once non-BI consumers (an internal app, an AI assistant) need the same numbers.
Moving from the first option to the third later means rebuilding every dependent report, so it is worth deciding deliberately rather than by default. A useful test: count how many distinct tools — not just BI dashboards, but spreadsheets, notebooks, an internal app, an AI assistant querying the warehouse — will need this metric within the next year. One or two tools rarely justify a standalone layer; three or more usually do.
Model the warehouse before you model the metrics
A metrics layer sitting on top of poorly structured tables inherits every problem those tables have. Get the data modeling right first: a clean star schema — fact tables at a clear grain, joined to conformed dimension tables — makes every metric definition shorter and every join unambiguous. Layering a semantic model on top of a tangle of denormalized, inconsistently joined tables just moves the ambiguity one level up and makes it harder to see.
-- fact table at order-line grain, the base most revenue metrics build on
select
o.order_id,
o.order_date,
o.customer_id,
li.product_id,
li.quantity,
li.unit_price,
li.quantity * li.unit_price as line_revenue
from {{ ref('stg_orders') }} o
join {{ ref('stg_order_lines') }} li using (order_id)
where o.order_status = 'completed' A metric like gross_revenue is then a one-line aggregation of line_revenue — trivial to write correctly because the hard modeling decisions (what counts as completed, what grain to aggregate from) were already made once, upstream.
Govern the definitions, not just the tooling
The tool matters less than the process around it. For each metric:
- Name it precisely and keep a business glossary entry alongside the code definition, in plain language, so a non-technical stakeholder can confirm the code matches their intent.
- Version it. A change to what "active" means is a breaking change for every downstream report; treat it like one, with a changelog and advance notice, not a silent SQL edit.
- Assign an owner per metric domain — usually the analytics engineer or finance analyst closest to that part of the business — who reviews proposed changes.
- Write a lightweight data contract for metrics that feed systems outside the data team, such as a metric synced into a CRM or used in a public-facing report, so a change is flagged before it breaks a dependent system rather than after.
Performance: precompute what gets queried often
A semantic layer that recomputes a heavy aggregation on every dashboard load is slow and expensive. Most implementations support some form of pre-aggregation or materialized view behind the definition, refreshed on a schedule, so the metric is both correctly defined and fast to query. Decide the refresh cadence per metric — a daily revenue number can refresh nightly; a real-time operations metric cannot.
Roll it out gradually
Start with the two or three metrics disputed most often — usually revenue, active users or a core conversion rate. Migrate their consumers one dashboard at a time, verifying the new number matches the old one (or documenting exactly why it does not, if the old one was wrong). A metrics layer that launches with fifty definitions and no adoption plan becomes one more place a definition can live, on top of the ones it was meant to replace.
Common mistakes
- Building the layer before agreeing on the definitions. The tooling decision is easy compared with getting finance, product and marketing to agree what "customer" means across their three different systems.
- No data lineage visibility. When a number changes, whoever is asked "why did revenue move" needs to trace it back to the models and raw sources that fed it, quickly.
- Treating it as a one-time project. New metrics get requested continuously; without an intake process, teams route around the layer with their own dashboard-level SQL, recreating the original problem.
Pair this with establishing data governance for the ownership model, and with building a dashboard people use once metrics are centrally defined. Semantic layer and BI tools are browsable at semantic and metrics layers and BI and dashboard platforms.