Metrics and Measures
Disambiguate the two things called a "metric" in Celiq โ node-level CML measures and the Context Studio Metrics tab, and learn how each is classified.
measures (aggregate SQL) you define inside a node's CML, and the Metrics tab in Context Studio, which lists your published business metrics.When to use it โ Use node measures whenever you need an aggregation (revenue, order count, margin) to be queryable in Discover and Orion. Use the Context Studio Metrics tab to review and certify the business-level metrics you expose to the rest of the workspace.
Where to find it โ Node measures live in Forge, inside each node's CML under
measures:. The Metrics tab is in Context Studio โ Semantic Layer โ Metrics.Who can use it โ Weavers author node measures in Forge; Luminaries certify metrics in Context Studio. Tracers and Lens can query the results but do not author them.
The word "metric" shows up in two places in Celiq, and they are not the same thing. The first is a node-level measure โ an aggregate calculation (SUM, COUNT, AVG) you write in a node's CML. The second is the Metrics tab in Context Studio, which despite its label actually lists your Reveals โ the named, business-facing metric layer. This page explains both, how Celiq decides whether a field is a measure or a dimension, and how the two layers fit together.
Overview
A node measure is a single aggregation defined on a node. In CML it lives in the measures: array (Celiq normalizes that key to metrics internally โ see Concepts). Each measure has a name, an aggregate sql expression, and optional metadata such as type, format, verified, and alert_threshold. Measures are the raw arithmetic of your model: total_revenue, order_count, gross_margin.
The Context Studio Metrics tab is a curated index. It is served by GET /api/context/metrics, which calls listReveals and returns one entry per Reveal across all your domains โ not per node measure. In Context Studio's own help copy: "Each metric is a Reveal โ a named calculation defined in a domain inside Forge." So when you open the Metrics tab, you are looking at the business-metric layer, with certification status, usage counts, and conflict detection โ not the per-node measures arrays.
Both layers are authored in Forge. The difference is altitude: node measures are the building blocks; Reveals are the polished, certified metrics that Orion and dashboards prefer.
When to use it
| You want toโฆ | Use |
|---|---|
Make SUM(revenue_usd) queryable on a node | A node measure (measures: in CML) |
Reuse one measure inside another ({a} / {b}) | A node measure with a metric reference |
| Expose a clean, named business metric to the workspace | A Reveal (shown in the Metrics tab) |
| Certify a metric as production-ready | The Metrics tab in Context Studio |
| Catch two domains defining the same metric differently | The Metrics tab (conflict detection) |
If you only ever need an aggregation available for ad-hoc Discover queries, a node measure is enough. If you want a metric to be governed, certified, and prioritized in Orion answers, promote it into a Reveal.
Concepts
Measure / metric (the CML key). In a node's CML you write the aggregate undermeasures:. The schema normalizer (cmlSchema.js) renames measures โ metrics as part of its canonical form, alongside renaming fields/dimensions โ attributes. So "measure" (what you type) and "metric" (the normalized key) refer to the same node-level object.
Attribute vs. metric. An attribute is a group-by column (a dimension). A metric is an aggregation. The normalizer auto-classifies fields: anything that looksLikeMetric is moved into metrics; everything else stays in attributes.
looksLikeMetric. A field is treated as a metric if it has an intent (e.g. sum, count, avg) or its sql matches an aggregate pattern โ SUM(, COUNT(, AVG(, MIN(, MAX(, or COUNT DISTINCT(. If you accidentally put an aggregate field in your dimensions list, the normalizer moves it to metrics and warns you.
metricClassifier (dimension blocklist). Some numeric columns must never be aggregated โ latitude/longitude, anything ending in _id, sequence/rank/position/index, zip/postal/phone codes, and integer status flags (is_, has_, flag_). The classifier's matchesDimensionPattern flags these so SUM(latitude) or AVG(zip) never sneaks in.
Reveal. A named business metric defined in a domain (the reveals: array). Reveals are what the Context Studio Metrics tab lists. See Reveals for the full model.
Metric reference. Inside a measure's sql you can reference another measure on the same node by name in braces โ {total_revenue} / {order_count} โ instead of repeating its SQL.
Getting started
You author node measures in Forge and review the curated metric layer in Context Studio. To work with either:
- You have a domain with at least one node bound to a warehouse table (see Forge).
- You are a Weaver (to author measures) or a Luminary (to certify metrics).
- To open the curated list: go to Context Studio, open the Semantic Layer group in the left nav, and click Metrics.
Step-by-step
Open the node in Forge
In Forge, select the domain and open the node whose CML you want to edit. Node measures live in the same CML file as the node's dimensions.
Add a measures block
Under the node, add a measures: array. Each entry needs at least a name. Give it an aggregate sql expression; without sql, locus, or column, the measure defaults to COUNT(*) and the validator warns you.
Set type and format
Add type (e.g. currency, integer, percentage) and an optional format string so the value renders correctly everywhere it's shown.
Mark verification and thresholds
Set verified: true once you trust the definition. Optionally set alert_threshold for measures that should trigger alerts (e.g. a return-rate ceiling).
Save and read the warnings
On save, the schema normalizer validates the node. It renames measures โ metrics, moves any aggregate fields out of attributes, and warns about COUNT(*) defaults or columns that look like dimensions. Resolve any warnings.
Promote to a Reveal (optional)
To make the metric a governed, workspace-facing business metric, define it as a Reveal in the domain. It then appears in the Context Studio Metrics tab, where a Luminary can certify it.
Examples
A realistic measures block from an orders node. Note the type/format/verified/alert_threshold metadata and the metric-references-metric pattern in avg_order_value.
measures:
- name: total_revenue
sql: "SUM(CASE WHEN status NOT IN ('cancelled','returned') THEN revenue_usd ELSE 0 END)"
type: currency
currency: USD
description: >
Net revenue excluding cancelled and returned orders.
Primary revenue KPI used in board reporting.
format: "${value:,.0f}"
owner: finance-team
verified: true
alert_threshold: null
- name: order_count
sql: "COUNT(DISTINCT order_id)"
type: integer
description: Total number of distinct orders placed
verified: true
alert_threshold: null
- name: avg_order_value
sql: "{total_revenue} / NULLIF({order_count}, 0)"
type: currency
description: Average revenue per order. Excludes cancelled/returned.
format: "${value:,.2f}"
verified: true
- name: return_rate
sql: "COUNT(CASE WHEN status = 'returned' THEN 1 END) / NULLIF(COUNT(*), 0)"
type: percentage
description: Percentage of orders that were returned.
verified: false
alert_threshold: 0.15
Here avg_order_value reuses the other two measures with {total_revenue} / NULLIF({order_count}, 0) instead of re-writing both aggregates. return_rate carries an alert_threshold of 0.15, the ceiling above which it should raise an alert.
Best practices
- Write the aggregate in
sql, never leave it implicit. A measure with nosql,locus, orcolumnsilently becomesCOUNT(*). Be explicit. - Use metric references to avoid drift. Define
total_revenueandorder_countonce, then buildavg_order_valueas{total_revenue} / NULLIF({order_count}, 0)so a change in one place propagates. - Always guard division. Wrap denominators in
NULLIF(..., 0)to avoid divide-by-zero, as in the example above. - Set
verified: truedeliberately. Treat it as a signal that the definition has been checked, not a default. - Keep measures on nodes; keep business metrics as Reveals. Use node measures for raw arithmetic and promote the metrics you want governed and certified into Reveals.
Tips
The Metrics tab in Context Studio lists Reveals, not node measures. If a metric you expect to see is missing, it is probably defined only as a node measure and has not been promoted to a Reveal yet. Conversely, if you are looking for raw SUM/COUNT definitions, open the node's CML in Forge โ they are not in the Metrics tab.
Common mistakes
dimensions/attributes. If a field's sql contains SUM(, COUNT(, AVG(, etc. โ or it has an intent โ the normalizer treats it as a metric and moves it out of attributes, warning "Moved N aggregate field(s) from attributes โ metrics." Author aggregates under measures: from the start.Aggregating a dimension-like column. Defining a measure whose underlying column matches the dimension blocklist โ anything ending in
_id, latitude/longitude, zip/postal codes, sequence/rank/position, or is_/has_/flag_ columns โ triggers the warning "'COUNT(DISTINCT ...) of an ID column is allowed; SUM(id) is not.Expecting node measures in the Metrics tab. The tab is the Reveal layer. A node measure does not appear there until it is exposed as a Reveal.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Warning: Metric "X" has no sql, locus, or column โ will default to COUNT(*) | The measure has a name but no aggregate expression | Add an explicit sql (or locus/column) to the measure |
Warning: '<col>' looks like a dimension attribute, not a measure | The measure's column matches the dimension blocklist (IDs, lat/lng, zip, sequence, status flags) | Move it to attributes, or if you genuinely need a count, use COUNT(DISTINCT <col>) |
Warning: Moved N aggregate field(s) from attributes โ metrics | An aggregate field was placed in fields/dimensions/attributes | Intended behavior โ confirm the field belongs under measures: and re-save |
Error: A metric is missing a name | A measure entry has no name | Add a name to every measure |
Error: Missing required field: node | The CML has no node (or name) key | Add the node name |
| Metric absent from the Context Studio Metrics tab | It is only a node measure, or its Reveal has no description and no usage | Promote it to a Reveal with a description, or query/certify it so it carries signal |
| A metric shows a conflict flag in the Metrics tab | Two domains define a Reveal with the same name but a different domain and description | Reconcile the definitions in Cross-Domain |
Related pages
- Reveals โ the business-metric layer that the Metrics tab actually lists
- Dimensions โ the attribute side of the dimension-vs-measure split
- Calculated fields โ derived fields and expressions
- Forge โ where you author node CML, measures, and Reveals
- Semantic layer overview โ how nodes, measures, and Reveals fit together