Metrics & Governance
Lifecycle: export, import & restore
Dashboards, data models and governed metrics can leave a workspace as definitions — portable JSON artifacts with no data and no credentials in them — and be imported into another workspace. Alongside that, dashboards carry immutable version snapshots, a field-level diff, and a restore. Together they cover the dev → prod path: build in one workspace, export, import, promote, and roll back if it goes wrong.
Export a definition
Section titled “Export a definition”Every list page has an export affordance:
| Where | Control |
|---|---|
| Dashboards list | Export definition in the card’s ⋯ menu (More actions for <name>) |
| Data Models list | a download icon on the row (hover) — accessible name Export <name> |
| Metrics hub | an Export button on the row (hover), or in the metric’s drawer |
You get a lowercase, filesystem-safe name with spaces and punctuation other than ., _ and - replaced
by hyphens: <name>.<assetType>.json, for example
q3-revenue.dashboard.json.
What is (and isn’t) in a definition
Section titled “What is (and isn’t) in a definition”This is the part that matters most, so be precise about it. An exported artifact contains no data, no credentials, and no workspace IDs. Every binding to something workspace-local is replaced by a symbolic reference:
| Reference | Means |
|---|---|
$model:0, $source:0, $metric:0, $query:0 |
a positional reference — you map it to a real object at import ($query:0 is the saved query a metric reads) |
$field:{tableAlias}.{fieldName} |
a model field, resolved by name in the target model |
$table:{tableAlias} |
a model table, resolved by alias |
$measure:{name} |
a SquareX measure, resolved by name |
The positional references are listed in the artifact’s references block with
their original names, so the import screen can show you “Orders Model”
rather than a bare token.
Serialization is deterministic — sorted keys, no timestamps, and symbolic references instead of workspace-local UUIDs — so the same unchanged asset exports byte-identical every time. That is what makes these files git-diffable: commit them, and a pull request shows exactly what changed.
Dashboard artifacts also embed definitions for dashboard-bound saved queries (name, SQL, description, and a symbolic source reference). Import recreates those queries with fresh IDs before it creates the cards, so saved-query cards do not arrive as “Not configured.”
A metric’s artifact carries its whole definition:
what it reads ($model:0, or $query:0 for a
metric on a saved query), its
expression, time dimension, grain, filters, how it adds up, a ratio’s parts,
settlement lag and close day, and its target, thresholds, format, Better
when, description and domain. Its owner and its certification stay behind. A
saved query is named in the file only when the person exporting may read saved
queries.
Import a definition
Section titled “Import a definition”Click Import on the Dashboards, Data Models or Metrics list (or Import a definition on the New dashboard page). The Import a DataSquares export dialog opens.
- Paste the JSON into Exported artifact (paste the JSON, or choose a file), or pick the file with Choose file. Invalid JSON shows “Not valid JSON yet.”, and JSON that isn’t an export says This isn’t a DataSquares export artifact — it’s missing …
- As soon as the JSON parses as an export, the Map references to this workspace
section appears — one row per positional reference, labelled with its
original name (e.g.
Orders Model (model),Prod Postgres (source)). Pick the matching object in this workspace from each dropdown (they start at choose…). - Optionally press Check — a dry run that resolves everything without writing, and reports anything it couldn’t match and any saved query of a dashboard that fails the safety check.
- Press Import.
Import stays disabled until every required reference is mapped. Mapped IDs are validated against the current workspace, so you cannot graft an asset onto another tenant’s model.
A dashboard’s saved queries pass the same safety check as
saving a query, in the SQL of the source each is
mapped to: a statement that would be refused when run (anything but a single
read-only SELECT or WITH query that DataSquares can parse in that source’s
SQL) is refused. Check lists each refused query with the check’s reason,
and Import stays disabled while the list stands. If any query is refused,
the whole import is refused: no dashboard, saved query or card is created, and
the error names each query with its reason. Changing a mapping clears the
list, since another source may read a query differently; press Check
again. A hand-edited definition whose query names a data source outside this
workspace is refused as not found.
The API has an allowUnresolvedFields escape hatch, but the web dialog does
not expose it. In the UI, unresolved $field, $table, or $measure
references block the real import after Check reports them.
A metric on a saved query maps its $query:0 row to one of this workspace’s
saved queries (the first 200 by name). Someone who may not read saved queries
is told You can’t read this workspace’s saved queries, so the metric’s saved
query can’t be mapped. Ask someone who can open the SQL editor.
An imported metric is made as Create metric makes one: its formula is checked against the mapped data model or saved query (a part that fails is refused, named), it starts at version 1, it is owned by you, and the import is in the audit log.
Import a metric over an existing one
Section titled “Import a metric over an existing one”A metric’s file has Import as: A new metric (Makes a new metric from the file, owned by you.), or, under Update an existing metric, one of this workspace’s metrics, which the file is imported over: Updates Revenue and keeps it, so its cards, alerts and decks read the file’s definition. Check shows what changes before anything is written. This is how a changed definition is promoted from a test workspace to a live one without breaking what uses it.
Check shows the plan first, and Update stays disabled until it has:
- Updates Revenue: 2 changes, each part by its name (Period: month → quarter, Filters [0].value: EU → US), or Revenue already matches this file: there is nothing to update.
- the version it makes, Makes version 4 (it is at version 3): what it computes changes., or Makes no new version: only how it is named and shown changes.;
- It clears Revenue’s certification: its new version must be certified again., when it does;
- anything that would refuse it, under It can’t be imported over Revenue while:, such as a certified metric that only its owner or a workspace admin may change.
A new target or a new mapping makes the plan stale: Check again. An update
writes only the parts that change, as an edit does, and needs the Metrics
edit permission. Through the API it is POST /api/alm/import with targetId,
whose dry run is the plan.
What import does, and what it does not
Section titled “What import does, and what it does not”Import creates a new asset — except a metric imported over an existing one (above), and a pipeline, which is updated in place. It does not update, merge into, or overwrite an existing dashboard or model. Treat the artifact as the source of truth and the import as a deploy of a new object, not an in-place upgrade.
Metric names are unique per workspace, so a collision is different: Check
reports the conflict and the dialog proposes <name> (imported), with Update
Revenue instead to import over the metric of that name. Choose a different name,
or update it, before importing. Dashboard and model imports still mint a new
asset rather than updating one with the same name.
Once the positional refs are mapped, fields, tables and measures resolve by name against the target model. If the target model’s aliases and field names match the origin’s, everything binds. If they don’t, you get an amber warning — “Unresolved in the mapped model (aliases/field names must match):” — with the list. Fix the target model’s naming, or re-export from a workspace that matches.
Versions, diff & promotion
Section titled “Versions, diff & promotion”Open a dashboard in the editor and choose Versions on the rail at the left (the command Versions & deploy does the same). (It’s hidden in preview mode, and needs edit permission.) The drawer says Each publish is a version. Compare it with the draft, restore it, or move it through the deployment stages.
Publish New Version snapshots the dashboard — name, description, layout, theme, filter state, pages, cards and filters — as an immutable version. The strip shows the current version number and whether it’s Published or Draft — publish to deploy, the deployment stages, plus the Version history (latest 10). Each stage shows the version deployed to it, or Not deployed, and requires publish when it does. With no published version yet, it says No versions published yet. Publish to start the deployment pipeline.
Versions, on the editor’s rail: the current version and whether it is published, Changes since the last version, Publish New Version, the deployment stages (none until some are added through the API) and the version history, each with diff and restore.

The diff
Section titled “The diff”The diff compares two snapshots field by field and reports one entry per changed leaf, with readable paths — cards and filters are matched by ID but labelled by title, so you read:
cards."Revenue by month".chartSpec.yFields[0].aggregation sum → avgThe summary counts + added, − removed, ~ changed, and an unchanged comparison says “No differences — the two versions are identical.”
You reach it from four places:
| Control | Compares | Gates anything? |
|---|---|---|
Changes since v{n} |
the published version → your working state | no — preview |
| diff (per version row) | the previous version → that version | no — preview |
Promote to {stage} |
the version already on the stage → the one you’re promoting | yes — see below |
| restore | your working state → the version you’re restoring | yes — it’s the confirm step |
Promotion
Section titled “Promotion”Promote to {stage} deploys to the next stage in your pipeline. What it deploys is the dashboard’s latest
published version, or, when the next stage requires publish, a new version it publishes from the working state
first (Auto-published on promotion to ‘…’). When the target stage already has a different version deployed than
the stage you promote from, the diff opens first as a confirmation, and the deploy only fires when you confirm
Promote v{n} to {stage}. The diff compares the two stages’ versions, so when the dashboard has been published, or
edited for a stage that requires publish, since the source stage was deployed, the version deployed can be newer than
the one the diff shows: publish and deploy in order to keep them the same.
On a stage with nothing deployed, Deploy v{n} deploys the newest published version to it. The editor has no
control to deploy an older version, to take a version off a stage or to change the stages: those are API-only.
POST /api/dashboards/{id}/deploy deploys any version to any stage (rolling a stage back is deploying an older
version to it), DELETE /api/dashboards/{id}/deploy/{stage} takes the dashboard off a stage, and
GET/POST /api/dashboards/stages and DELETE /api/dashboards/stages/{stageId} list, add and remove the workspace’s
stages (a stage a dashboard is deployed to can’t be removed). Workspaces created since stages were introduced start
with none, so their Versions drawer shows no stages until some are added through the API. Promoting and deploying
are not recorded in the audit log.
Deleting a dashboard
Section titled “Deleting a dashboard”Company admins can delete a dashboard from the library. It leaves the library at once and waits in the Recovery Center for the workspace recovery window. The one exception to needing the delete permission is a draft you created and never touched — see Drafts nobody touched.
Open Dashboards and find the dashboard, here by searching its name. Deleting needs the delete permission on dashboards, which company admins have and the author role does not.

A confirmation titled Move dashboard to Recovery Center says the dashboard and its cards move to Recovery Center, where an admin can restore it for 30 days (the workspace recovery window). Choose Move to Recovery Center to go ahead, or Cancel to keep the dashboard in the library.

The dashboard leaves the library and waits in the Recovery Center for the workspace recovery window; someone with the restore permission can bring it back (see the Recovery Center walkthrough).

The Recovery Center, step by step
Section titled “The Recovery Center, step by step”Deleted dashboards, reports, stories, presentations and metrics wait in the Recovery Center. Restoring needs the recovery restore permission.
Open Recovery. Deleted dashboards and reports wait here for a limited time before they are gone for good.

Search for a deleted item, or filter by Type (dashboards or reports) and Status (restorable, or window closed).

View details shows what restoring would change. Restore is deliberately safe: the definition returns unpublished, and public links, schedules and alerts stay off until an owner reviews them. Restoring needs the recovery restore permission.

Each row says how the item left. A person’s delete reads Deleted, the time and the person’s name. A draft the system cleared reads Removed automatically, the time, and an untitled draft nobody changed for 7 days — no person is named, because none deleted it.
Preview restore opens the restore dialog. It starts with what to know before the item comes back, under Before you restore (1 public link will stay disabled. Published state remains off until the restored item is reviewed and published again.), then lists What returns and what Stays disabled. Restore safely restores it.
Stories in the Recovery Center
Section titled “Stories in the Recovery Center”A deleted story waits like a dashboard or report, for the same recovery window, and the Type filter has a Stories choice. Nothing of it is removed while it waits — its sections, versions, comments, review rounds and decisions, follows and activity all stay — so a restore brings it back whole, with the two differences dashboards and reports have:
- It comes back unpublished. A published story returns as a draft, with its versions kept in its history; publish it again when it is ready. An archived story stays archived.
- Its access grants are removed. The people and groups it was shared with lose that access, and the preview says how many to add again. A review round that was open stays open, and its reviewers can open the story again once you share it with them.
A story has no public links, schedules or alerts, so there are none to switch off. It also keeps the privacy a story has everywhere else: you see a deleted story in the Recovery Center — in the list, the counts and Recent recoveries — only if you could have read it, meaning you own it, you are an admin, it was published and your role can view Stories, or it was shared with you directly or through a group. Restoring needs the recovery restore permission, as for the others, and leaves a receipt and an audit event.
Presentations in the Recovery Center
Section titled “Presentations in the Recovery Center”A deleted presentation waits like a story, with the same privacy, and comes back the same way: as a draft, with its versions, records and comments kept and its access grants removed. Its schedules are switched off and counted in the preview and the receipt, as a dashboard’s and a report’s are, so publishing it again never resumes mailing its people and groups by itself: turn each schedule on again when it should send.
Metrics in the Recovery Center
Section titled “Metrics in the Recovery Center”A deleted governed metric waits for the same recovery window, under the Type filter’s Metrics choice. It comes back with its own id: its definition, versions, owner, domain, target and certification return, and the dashboard cards, deck and story figures that name it read it again. What it reads is read again as it comes back: when its saved query, a measure or a field under it changed while it was deleted, it comes back as its next version, uncertified, and its owner is told. What returns says so.
A delete made while something used the metric turned its alerts and activations off and took it out of its digests. They stay that way for their owners to turn on again: Stays disabled names each one (Alert “Revenue under plan”, Digest “Monday numbers” no longer lists it), and the receipt counts the alerts. The anomaly sweep’s own record of the metric, and an alert that was already off before the delete, are not among them. A restore is refused when a live metric has taken its name, or when what it read was deleted since.
Before you restore says the same in sentences (Its delete turned off alert “Revenue under plan”: they stay off until their owners turn them on.), and the toast that says it is restored (Revenue restored safely) lists them again, with a line when it came back as a new version (What it reads changed while it was deleted, so it came back as version 4 and is no longer certified: an admin certifies the new version again.).
Drafts nobody touched
Section titled “Drafts nobody touched”Blank dashboard, Blank report and Blank story (and the other ways on the New … pages that open an editor) create the item at once — the editor needs somewhere to save to — so opening one and leaving without adding anything leaves an Untitled Dashboard, Untitled Report or Untitled story behind. Two things stop these piling up:
- You can delete your own. The Editor role can create and edit content but not delete it; for a draft you created and have not touched, that does not apply. The Dashboards list offers Move to Recovery Center in its ⋯ menu and the Reports list Delete on it, and a story’s owner deletes it from the story’s ⋯ menu; it moves to the Recovery Center like any deleted item. Anyone else’s draft, and anything that is more than a draft, still needs the delete permission. A saved query you created that nothing uses can be deleted without that permission too — see Deleting a saved query of your own — but a saved query’s delete is permanent: it does not wait in the Recovery Center.
- Untouched drafts are removed after 7 days. A sweep that runs every hour removes a draft that is still untouched and that nobody has changed for 7 days. It waits in the Recovery Center for the recovery window like any deleted item, marked Removed automatically. The audit log records the removal as
dashboard.deleted,report.deletedorstory.deletedwith no user and the reasonuntouched_draft, and webhooks subscribed todashboard.deletedorreport.deletedreceive it with that reason in place ofdeletedBy.
Untouched means all of this, so one change — a new name, a card, a line of text — makes the draft an ordinary one that is never swept:
| Untouched when | |
|---|---|
| Dashboard | still named Untitled Dashboard, with no description, cards, filters or saved versions, and never published |
| Report | still named Untitled Report, not a template, with no description, blocks, filters, table definition, versions or schedules, and never published |
| Story | still titled Untitled story, with no summary or saved version, no section that has a title, an assignee, a due date, text or AI-written content, and never published |
The 7 days is fixed. It is not the workspace recovery window, which is how long a removed item can then be restored.
Restore
Section titled “Restore”In Version history, every version other than the current one has a
restore link. Clicking it opens the diff (Restore v{n}) — each changed field with your working state’s value
struck through, then → and that version’s value — and the confirm button reads
Replace working state with v{n}.
Restore replaces the dashboard’s working state with the snapshot (keeping the original card and filter IDs), then auto-publishes, so the restore is itself a new version. Nothing is lost: the history records that the new version was restored from the old one, and you can restore back out of it.
Restore a data model
Section titled “Restore a data model”Publishing a data model now stores a real definition snapshot. Open the model’s Version history and choose Restore on an older version to put its tables, relationships, fields, measures and policies back into the working definition. Existing IDs are preserved where possible so dashboard cards, filters and data-quality tests keep their bindings.
Model restore does not publish automatically and does not create another version. Review the restored working definition, validate it, and publish it when it is ready; that publish creates the next snapshot. The restore runs in one transaction and reconciles tables, fields, relationships, hierarchies, RLS policies, measures, and table transforms in dependency-safe order. When it changes what a governed metric of the model reads (a measure, a calculated field, the column a field reads), that metric gets its next version in the same transaction, its certification is cleared and its owner is told; the model’s other metrics are left as they are.
Version history starts with the first publish made after snapshot versioning was introduced; older version numbers do not have a snapshot to restore. The current model dialog executes Restore directly—there is no model diff or second confirmation step.
Walkthrough: change how long deleted items can be restored
Section titled “Walkthrough: change how long deleted items can be restored”Admins choose the recovery window for the workspace. The steps stop before saving.
Open Recovery in the sidebar. The Restore window card shows how long deleted dashboards and reports stay restorable; only admins see the Change button.

Choose Change, then enter a length in whole days. Longer windows keep deleted items restorable for longer; choose Save changes to apply it.

A shorter window takes effect immediately: items deleted longer ago than the new length can no longer be restored. The warning appears, and the button says Shorten restore window, so it is a deliberate choice.

Honest limits
Section titled “Honest limits”- Field-level diff, promotion stages and auto-publishing restore remain dashboard-only. Models have snapshot history and restore, but no promotion pipeline or pre-restore field diff. Metrics still have no version restore.
- Import always creates a dashboard or a model. There is no “update this existing dashboard from this artifact” path; only a metric (imported over an existing one) and a pipeline are updated in place by importing them.
- No approval step or Git sync yet. Release management on Enterprise is the import above; an approval before a release goes live, a side-by-side compare of two workspaces and Git sync are not built.
- Fields resolve by name, so renaming a field in the target model breaks imports that referenced it.
Related
Section titled “Related”- Data models & relationships — publishing and versioning a model.
- Canvas basics — the editor’s rail, where Versions lives.
- Catalog: certification & glossary — lineage and impact analysis before a change.
