Insights: backing a card with a metric¶
The Insights module lets you build live dashboards on Databricks. Cards on those dashboards have always been backed by raw SQL — you wrote a query, you got a chart. As of April 2026 a card can also be backed by a published metric from the Metrics module: pick a metric, pick a period, and the card runs against the metric's currently-published version on every refresh.
This page covers when to use a metric-backed card, what the connection rules are, how to add one, the lineage chip on the card header, and what the friendly empty states mean when something upstream changes.
If you are looking for how to define a metric in the first place, that lives at Metrics: defining and joining tables. This page assumes the metric already exists.
When to choose this¶
Use a metric-backed card when:
- The number you want on the dashboard is already a published metric in the Metrics module (or could be).
- You want the card and the metric page to stay in sync — every time the metric is edited, every dashboard that references it picks up the new definition on its next refresh.
- You care about lineage — when a steward asks "which dashboards depend on Revenue MoM?", the answer should be a single query, not a code review of dashboard SQL.
- The metric and the dashboard live on the same Databricks connection. Cross-connection metric references are blocked by design (see § Connection policy).
Stick with a SQL-backed card when:
- The query is dashboard-specific and would never be reused (a one-off slice, a debugging tile, an exploratory chart).
- You need a column or shape that the metric layer doesn't expose (free-form joins across catalogs, ad-hoc CTEs).
- The metric layer doesn't yet model what you need and you don't want to wait for one to be published.
You can mix both kinds of card on the same dashboard. The data source is per-card, not per-dashboard.
Connection policy — why cross-connection references are blocked¶
Every dashboard in Datahub is bound to one Databricks connection (an integration). Every published metric is also bound to one Databricks connection — the one its source tables live on. We require these two to match before you can point a card at a metric.
This is not arbitrary:
- Authentication identity stays consistent. When you open a dashboard with Databricks per-user OAuth (see Databricks: per-user OAuth), the dashboard requests one access token, scoped to the dashboard's connection. A metric living on a different workspace would need a different token, which means a different consent flow — silently, mid-render. We don't do that.
- Unity Catalog RLS stays predictable. Per-user row-level security applies on the warehouse the token authorises. A metric reaching across to a different warehouse would either bypass RLS or fail opaquely, depending on permissions. Both are bad.
- The dashboard tells the truth. If the dashboard says "this is data from
prod-eu-warehouse", every card on it should queryprod-eu-warehouse. No exceptions.
If you try to point a card at a metric on a different connection, the create / update endpoint returns 409 Conflict with a clear "metric integration does not match dashboard integration" message. The metric picker on the Add Card flow will not even offer such metrics — it pre-filters to only metrics published on the dashboard's connection.
If you genuinely need the metric on a dashboard on a different warehouse, republish the metric on that warehouse (the metric definition is portable; only the source-table binding is connection-specific). See Metrics → Where my metric reads from for how source binding works.
Setup — what an admin needs to do once¶
Nothing module-specific. The metric-backed card flow re-uses everything that was already in place:
- The Metrics module is enabled (it is by default — see Module Management at
/admin/modules). - The user has at least
metric.read(built into every authenticated role group's baseline). - The user has
insights.manageto add or edit cards. - There is at least one active, published metric on the dashboard's Databricks connection.
If item 4 is missing, the picker will tell you so and link back to the Metrics module to publish one.
Per-user steps — adding a metric-backed card¶
- Open the dashboard in edit mode (
/insights/{id}/edit). - Click Add card in any empty slot, or + in a section.
- In the card modal, switch the Data source toggle from From SQL to From Metric.
- Pick a metric from the Metric dropdown. The list is already filtered to metrics that are:
- Active (not archived)
- Published (not draft)
- On the same connection as this dashboard If the dropdown is empty, the panel will explain why and what to do.
- Pick the runtime parameters that will be passed to the metric on every refresh:
- Period grain —
day,week,month,quarter,year,fiscal_quarter, orfiscal_year. Defaults tomonth. - Period start / end — the window the card will report on. Defaults to the last 12 months.
- Compare — what to compare the current window against. Options include
pop,wow,mom,qoq,yoy_calendar_aligned,yoy_fiscal_aligned,custom_window. Defaults toyoy_calendar_aligned. - Comparison start / end — only shown when Compare is
custom_window. - Configure Display and Filters as you would for any card (chart type, colour, format, …).
- Save.
You will see a one-line note in the modal: "Metric-backed cards run against the published metric on save — preview will appear on the dashboard." That is intentional — see § Why no in-modal preview.
After saving, the new card appears on the dashboard. Refreshing the dashboard runs the metric end-to-end through MetricQueryService.query() on every refresh — there is no snapshot.
Editing metric-backed cards¶
You can change a metric-backed card the same way you edit any card: open the dashboard in edit mode, open the card, and use the Data source area. You may switch the metric, period grain, date range, and comparison (for example month-over-month vs year-over-year) without leaving the card. Chart and table column pickers only offer columns that belong to the metric’s fixed result shape (time, value, comparison, and delta) — you do not pick arbitrary warehouse columns.
If the card is SQL-backed and you want to promote it to a governed metric, use From metric, pick a published metric on the same connection, and confirm when the product warns that your SQL will be replaced. The reverse (metric back to SQL) is also available with the same kind of confirmation, so you do not lose work silently.
Letting HERC bind a card to a metric¶
While a card is open in the editor, open HERC on that card. Ask in plain language to use a specific KPI or a published metric (for example to show revenue month-over-month from the catalog). HERC lists metrics that are available for this dashboard’s connection, then can apply the binding to the form. You still Save the card to persist the change. You need permission to manage insights cards and to read metrics; if listing or binding is blocked, HERC will say what is missing.
Asking HERC to publish a metric for me¶
If no published metric matches what you need, you can ask HERC to help draft and publish a new metric, then bind the card to it. HERC will use your tenant’s metrics workflow (draft specification and publishing) under your account. Publishing requires metric write access; without it, you will see a clear refusal and you can ask a steward to publish, or use the Metrics module’s wizard yourself. The primary place to design and own metrics long-term remains the Metrics module; HERC is there so you are not forced to hand-write SQL on the card when a governed path exists.
The lineage chip on the card header¶
Every metric-backed card shows a small chip beneath the card title:
Backed by Revenue MoM →
The chip is a clickable badge. Clicking it takes you to /metrics/{id} so you can inspect the metric definition, see who owns it, view its version history, and run the metric in isolation. This is the canonical way to answer "what is this number really measuring?"
If the underlying metric is archived, the chip switches colour and gains a small (archived) suffix. The card still renders if the published version is still queryable, but the chip is your warning that the definition is no longer the canonical one.
If the user viewing the dashboard does not have metric.read, the chip degrades to a generic "Backed by metric" label without the metric's name. The card still renders.
Empty states — what they mean and what to do¶
Metric-backed cards bypass the generic "query failed" alert in favour of in-card empty states that tell you what went wrong upstream and what to do next. The four states you can see:
| State | What it means | What to do |
|---|---|---|
| Metric is no longer available | The metric was hard-deleted (or metric_definition_id no longer resolves). |
Edit the card and pick another published metric on the same connection. |
| Metric has no published version | The metric exists but its current version is in draft state, or it was unpublished. |
In the Metrics module, publish the metric (or revert to a previously-published version). The card will recover on the next refresh. |
| Card configuration is incomplete | The card's saved metric_params is missing a required field (period, grain, or comparison). Usually only happens for cards created via API. |
Edit the card. The wizard will re-seed defaults you can adjust. |
| Dashboard has no connection | The dashboard's integration_id is not set. The metric layer cannot run without a target warehouse. |
Open Dashboard Settings, pick a Databricks connection. |
Every empty state includes a "Pick another metric →" link that takes you back to the dashboard editor. None of the four states is a bug; they are the metric layer telling you that an upstream curation step is needed.
Editing the metric — what flows downstream¶
Because metric-backed cards are live references, every edit in the Metrics module is immediately visible to dashboards that reference the metric:
| You edit the metric to… | Effect on dashboards that reference it |
|---|---|
Change the measure expression (e.g. sum(amount) → sum(net_amount)) |
Every refresh now reflects the new expression. |
| Add or remove a join | Every refresh runs the new spec. Cards using filters that referenced removed dimensions may need editing. |
| Change source binding (catalog/schema/table) | Every refresh reads from the new source. The dashboard's connection still has to match. |
| Move the metric to a different connection | All dashboards on the old connection that referenced it will fall into the Metric is no longer available empty state. Republish the metric on the dashboard's connection or repoint the dashboard. |
| Archive the metric | The lineage chip flips to the archived style. The card still renders if the published version is queryable. |
| Unpublish (revert the published version to draft) | Cards drop into the Metric has no published version empty state until republished. |
Stewards can answer "which dashboards depend on this metric?" by looking up cards.metric_definition_id in the database, or by following the lineage chip from any card.
Why no in-modal preview¶
The Add Card modal shows a "Run Query" preview button for SQL-backed cards. It is hidden for metric-backed cards. This is on purpose:
- The metric is already preview-able on its own page (
/metrics/{id}) with the full Run Query card, including grain/compare/period controls. - Running the metric inside the modal would require a parallel preview endpoint that duplicates the dispatcher's work; we'd rather have one execution path that the dashboard always uses.
- After save, the card appears on the dashboard immediately — that is the preview.
This trade-off is a deliberate product choice: one execution path on the live dashboard, preview on the metric’s own page.
Editing a card without leaving the dashboard¶
When you click the pencil icon on a card on /insights/{id}, the card editor now opens as a right-side slide-over panel instead of a centred modal. The dashboard stays visible behind the panel and everything outside the focused card dims out — the card you're editing remains in full colour with a soft accent ring around it. The viewer auto-scrolls so the focused card sits in the visible left strip beside the panel.
You can still:
- Open HERC from the card editor — the AI panel floats on top of the slide-over (it never gets hidden behind it) and keeps the editor's full context.
- Discard unsaved changes — closing the panel with the X, the Escape key, or by clicking the dimmed area asks for confirmation when you have edits in flight.
- Resize the browser — the spotlight cutout follows the card via a live resize observer, so the focus ring stays where the card is even as the layout reflows.
This pairs with the dense-page philosophy recorded in docs/adr/ADR-011 (internal): big multi-step flows live on full PageWorkspace pages; "edit one item without leaving the list" lives in a slide-over so you keep your bearings.
Limitations¶
- No version pinning. A card always runs the metric's currently-published version. There is no UI to freeze a card to a specific historic version. If you need a snapshot dashboard for, say, a quarterly review, take the snapshot at the dashboard level (export, archive, or copy).
- No cross-connection references. Documented above; this is by design, not a bug.
- No metric-on-metric composition inside a card. A card references one metric. If you need two metrics side-by-side, use two cards.
- Period parameters are per-card. Two cards backed by the same metric can have different periods/grains/comparisons. There is no dashboard-level "metric period" that cascades to all metric cards.
- Card-level filters do not narrow the metric. Filters defined on the card filter the result of the metric query (the same way they'd filter SQL output). Filters that need to push down into the metric's source query should be modelled inside the metric itself, not on the card.
When the data warehouse is warming up¶
A cold Databricks SQL warehouse can take one to three minutes to accept queries. When a dashboard card or a filter with dynamic options is still loading after a few seconds, HERC may offer a choice: keep waiting on the page, or notify you when the data is ready. If you choose Notify me and go elsewhere, you will get an in-app success toast with a View action that returns you to this dashboard. The same pattern is available on other long-running data surfaces in Datahub, not only Insights, so the behaviour will feel familiar as it rolls out more widely.
Audit & compliance¶
| Question | Answer |
|---|---|
| Does the card execute the metric under the dashboard viewer's identity? | Yes. Per-caller oauth_u2m token resolution applies — same RLS contract as SQL-backed cards. See Databricks: per-user OAuth. |
| Can a card on Dashboard A point at a metric on Connection B? | No. Mismatch returns 409 Conflict at create/update; the picker pre-filters them out. |
| Where can I find a list of every card that depends on a given metric? | Database: SELECT * FROM insights.cards WHERE metric_definition_id = '…' (admin / steward access). |
| What happens if I hard-delete the metric definition? | Cards drop into the Metric is no longer available empty state on the next refresh. Stewards should archive (not hard-delete) — see the platform's archive-before-delete policy. |
| Is the metric's compiled SQL ever stored on the card? | No. The card stores only metric_definition_id. The dispatcher resolves the published MetricVersion and its compiled_sql on every execute. |
Troubleshooting¶
- The picker is empty. No active, published metrics target this dashboard's Databricks connection. Either publish a metric on that connection or move the dashboard to a connection that already has metrics.
- I get a 409 when saving. The picker should never let this happen, but if you arrive via the API, the metric's connection does not match the dashboard's. Check the dashboard's
integration_idin Dashboard Settings. - The card renders the wrong period. Edit the card; the period/grain/compare live on the card, not the metric. The metric's own page may show a different default period — that is independent.
- The chip says (archived) but the card still renders. Expected behaviour while the published version is still queryable. Republish a current version (or pick another metric) before archiving the definition fully.
- The card briefly shows "Loading metrics…" forever in the editor picker. Reload the editor; this usually means the dashboard's
integration_idwas unset. Open Dashboard Settings and pick a connection.