Celiq
v0.12Open app โ†—
Docs/Semantic Layer/Metrics and Measures

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.

WeaverLuminaryUpdated June 2026 ยท 8 min read
โœฆ
In this section
Part of Celiq's semantic layer platform. Connect your warehouse, model your data once, query it everywhere.
๐Ÿ’ก
Tip
What it is โ€” Two related but distinct things that Celiq both calls a "metric": the 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 nodeA 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 workspaceA Reveal (shown in the Metrics tab)
Certify a metric as production-readyThe Metrics tab in Context Studio
Catch two domains defining the same metric differentlyThe 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 under measures:. 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

1

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.

2

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.

3

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.

4

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).

5

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.

6

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.

fct_orders.celiq
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 no sql, locus, or column silently becomes COUNT(*). Be explicit.
  • Use metric references to avoid drift. Define total_revenue and order_count once, then build avg_order_value as {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: true deliberately. 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

๐Ÿ’ก
Tip

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

โš ๏ธ
Warning
Putting an aggregate in 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 "'' looks like a dimension attribute, not a measure." 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

SymptomCauseFix
Warning: Metric "X" has no sql, locus, or column โ€” will default to COUNT(*)The measure has a name but no aggregate expressionAdd an explicit sql (or locus/column) to the measure
Warning: '<col>' looks like a dimension attribute, not a measureThe 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 โ†’ metricsAn aggregate field was placed in fields/dimensions/attributesIntended behavior โ€” confirm the field belongs under measures: and re-save
Error: A metric is missing a nameA measure entry has no nameAdd a name to every measure
Error: Missing required field: nodeThe CML has no node (or name) keyAdd the node name
Metric absent from the Context Studio Metrics tabIt is only a node measure, or its Reveal has no description and no usagePromote it to a Reveal with a description, or query/certify it so it carries signal
A metric shows a conflict flag in the Metrics tabTwo domains define a Reveal with the same name but a different domain and descriptionReconcile the definitions in Cross-Domain
  • 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