Item fields
These fields sit around the definition. An import file row uses them.| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | Yes | The identifier, for example average_order_value. Unique among metrics in the workspace, including archived ones. It can’t change after saving. Studio asks for lowercase with underscores. |
display_name | string | No | The name people see, for example “Average order value”. An import uses name when it’s missing. For a saved query, use the question. |
description | string | No | One or two sentences on what the number means. |
definition | object | Yes | The metric definition below, or the saved query definition. |
source_uri | string | No | Where the definition came from, for example a file path in your repository. Shown as Source location. Never fetched. |
source_version | string | No | The revision of that source, for example a commit. Shown as Source revision. |
source_metadata | object | No | Any other details about the source, kept as given. |
Metric definition
Spec version1.0-draft.4. Unknown fields are refused at every level. Put experimental data in extensions.
| Field | Type | Required | Meaning |
|---|---|---|---|
spec_version | string | Yes | The format version. Must be 1.0-draft.4. |
version | integer | Yes | The definition version. A whole number of 1 or more. Raise it when the calculation changes; see Version rules. |
dialect | string | Yes | The warehouse the SQL is written for, for example snowflake. Free text. Shown as Warehouse. |
formula | string | Yes | The expression or query that computes the number. Stored as written. |
aggregation | object | Yes | How the formula combines rows. See aggregation. |
output | object | Yes | The result column. See output. |
source | object | Yes | The table or SQL the metric reads. See source. |
population | string | No | In words, which rows the number covers. Shown as Includes. |
exclusions | array of strings | No | In words, rows the number leaves out. Shown as Excludes. |
grain | string | No | The row level the metric works at, for example order_id. Shown as Granularity. |
filters | array of strings | No | SQL conditions the metric applies. |
mandatory_filters | array of strings | No | SQL conditions marked as mandatory. Can refer to a parameter as :name. |
depends_on | array of strings | No | Names of other metrics this one is built from. Each name that matches a live metric in the workspace becomes a depends_on link. |
replaced_by | string | No | Name of the metric that replaces this one. Becomes a replaced_by link. Doesn’t withdraw or archive anything. |
joins | array of objects | No | Other tables the metric joins. See joins[]. |
dimensions | array of objects | No | Ways to break the number down. See dimensions[]. |
examples | array of objects | No | Questions the metric answers, with their SQL. See examples[]. |
provenance | object | No | How the definition was observed. See provenance. |
extensions | object | No | Any extra data. Kept as given, with a warning, and never interpreted. |
aggregation
| Field | Type | Required | Meaning |
|---|---|---|---|
type | string | Yes | One of sum, count, count_distinct, min, max, ratio, custom. Shown as Aggregation type. |
reaggregation | string | No | How the number rolls up across groups: sum, min, max, or none. Shown as Rolling up. |
null_handling | string | No | How missing values count: ignore, zero_fill, or propagate. Shown as Missing values. |
zero_denominator | any JSON value | No | What a ratio does when it divides by zero. Shown as Dividing by zero. |
output
| Field | Type | Required | Meaning |
|---|---|---|---|
alias | string | Yes | The result column name. Shown as Output name. |
datatype | string | Yes | One of integer, decimal, string, boolean, date, timestamp. Shown as Output data type. |
unit | string | No | For example USD or orders. Shown as Output unit. |
source
| Field | Type | Required | Meaning |
|---|---|---|---|
entity | string | Yes | What the rows represent, for example orders. Shown as Source entity. |
alias | string | Yes | The alias the formula uses, for example o. Shown as Source alias. |
table | string | One of table or sql | The table to read, for example analytics.sales.orders. |
sql | string | One of table or sql | SQL whose result the metric reads instead of a table. |
timeframe_column | string | No | The column that dates each row. Shown as Time column. |
parameters | array of objects | No | Values a caller supplies. Each has name (required, unique), datatype (required), and default (required, any JSON value, can be null). |
table and sql, and it can’t be empty.
joins[]
| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | Yes | Unique among the metric’s joins. |
to | string | Yes | The table or entity joined. |
sql | string | Yes | The join condition. |
cardinality | string | Yes | For example many_to_one. Free text. When a value ends in many, such as one_to_many, Studio warns that breaking the number down through the join can count a row more than once. |
origin | string | Yes | Where the join came from. Studio reads declared as stated in the definition and observed as worked out from past queries. |
dimensions[]
| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | Yes | Unique among the metric’s dimensions. |
kind | string | Yes | For example time or categorical. Free text. |
sql | string | Yes | The expression for the dimension’s values. |
datatype | string | Yes | The values’ data type. |
filter_form | string | No | How to filter on it, for example equals, in list, or range. |
values | array | No | Observed values, in the order given. |
values_truncated | any JSON value | No | Whether values is only part of the list. |
value_map | any JSON value | No | A mapping of values, kept as given. |
required_join | string | No | The name of a join in joins this dimension needs. It must exist. |
description | string | No | What the dimension means. |
examples[]
| Field | Type | Required | Meaning |
|---|---|---|---|
source | string | Yes | Who or what supplied the example. |
question | string | No | The question in words. |
group_by | array of strings | No | Dimension names. Each must exist in dimensions. |
filters | object | No | Filter values used, by name. |
parameters | object | No | Parameter values used, by name. |
sql | string | Yes | The SQL that answers the question. |
result | object | No | A sample result, as supplied. Atlan doesn’t verify it. Has columns (array of strings), row_count (integer), hash (string), executed_at (string), and rows (array of rows, each an array of strings or null). Every row needs as many cells as columns has. |
provenance
| Field | Type | Required | Meaning |
|---|---|---|---|
source | string | Yes | Where the observation came from, for example query_history. |
proposed_by | string | Yes | Who proposed the definition. |
execution_count | integer | No | How many times the observed SQL ran. |
distinct_analysts | integer | No | How many people ran it. |
trust_score | number | No | A score from your own tooling. It grants no access. |
observed_in | array of strings | No | Where it was seen. Never fetched. |
observed_sql | string | No | The SQL as observed. |
derived_from | array of strings | No | What it was derived from. Never fetched. |
Version rules
When you save a new revision of a metric, Atlan compares it with the current one:- If the calculation changed,
versionmust be higher. The calculation coversspec_version,dialect,formula,aggregation,output,filters,mandatory_filters,source,joins, the SQL parts ofdimensions(includingvalue_map),depends_on,grain,population,exclusions, andextensions. - If only
display_name,description,examples,provenance,replaced_by, or a dimension’svaluesordescriptionchanged,versioncan stay the same. versioncan never go down.
version by 1 each time you edit a metric. The definition version is separate from the revision number and the release version. See Three different version numbers.
Saved query definition
Spec version1.0-draft.1. Unknown fields are refused. Only spec_version and sql are required, but a field you include can’t be blank.
| Field | Type | Required | Meaning |
|---|---|---|---|
spec_version | string | Yes | Must be 1.0-draft.1. |
question | string | No | The question the SQL answers, up to 1,000 characters. The main text agents search on. Shown as Question. |
paraphrases | array of strings | No | Other ways to ask it. Up to 16, each up to 1,000 characters, each different from the question and from each other (ignoring case). |
sql | string | Yes | The SQL, up to 64 KiB. Stored as written. Shown as SQL text. |
dialect | string | No | The warehouse, up to 64 characters. Free text. Shown as Warehouse. |
parameters | array of objects | No | Named values the SQL expects. Each has name (required), data_type, and description. Names are unique, ignoring case. |
output_columns | array of objects | No | Result columns. Each has name (required) and data_type. Names are unique, ignoring case. |
analysis | object | No | Structure extracted by your own tooling: tables, columns, dimensions, measures, filters (each {column, operator, value}), and extractor, for example sqlglot 26.1. Atlan checks its shape only and never compares it with the SQL. |
usage | object | No | execution_count, user_count, and last_executed_at (an RFC 3339 timestamp), as you report them. |
review_status | string | No | unreviewed (default), verified, or rejected. Studio shows verified as Ran when saved: Yes and unreviewed as Not run. It’s your claim, not a check by Atlan. |
usage_note | string | No | Guidance for an agent reusing the query, up to 4,000 characters. Shown as Usage notes. |
extensions | object | No | Any extra data, kept as given with a warning. |
Fields Atlan adds
Atlan computes these on every save. Anything you send for them is replaced.| Field | Meaning |
|---|---|
definition_sha256 | A fingerprint of the whole definition. Key order and whitespace don’t change it. |
execution_definition_sha256 | Metrics only. A fingerprint of the calculation fields listed in Version rules. |
sql_sha256 | Saved queries only. A fingerprint of the SQL with whitespace collapsed, used to spot duplicate SQL. |
validation_warnings | Advisory warnings, listed below. They never block a save. |
sql_validation | Always not_performed. |
Warnings
| Warning | Applies to | When |
|---|---|---|
pilot_spec | Both | Always. The format is a preview format, and saving doesn’t prove the SQL or the number. |
draft_vocabulary | Metric | aggregation.type, reaggregation, null_handling, or output.datatype uses a word outside its list. |
ratio_policy | Metric | aggregation.type is ratio and zero_denominator is missing or null. |
examples_missing | Metric | examples is empty. |
experimental_fields | Metric | extensions has data. |
question_missing | Saved query | No question. |
dialect_missing | Saved query | No dialect. |
analysis_missing | Saved query | No tables in analysis. |
extensions | Saved query | extensions has data. |
Complete example
{
"name": "average_order_value",
"display_name": "Average order value",
"description": "Average amount a customer pays per completed order.",
"source_uri": "metrics/orders/average_order_value.json",
"source_version": "9f2c1e7",
"definition": {
"spec_version": "1.0-draft.4",
"version": 1,
"dialect": "snowflake",
"formula": "SUM(o.order_total) / COUNT(DISTINCT o.order_id)",
"aggregation": {
"type": "ratio",
"reaggregation": "none",
"null_handling": "ignore",
"zero_denominator": "return_null"
},
"output": {
"alias": "average_order_value",
"datatype": "decimal",
"unit": "USD"
},
"population": "Completed orders from the online store",
"exclusions": ["Test orders placed by staff accounts"],
"grain": "order_id",
"filters": ["o.order_total > 0"],
"mandatory_filters": [
"o.status = 'completed'",
"o.ordered_at >= :start_date"
],
"depends_on": ["revenue"],
"source": {
"entity": "orders",
"table": "analytics.sales.orders",
"alias": "o",
"timeframe_column": "o.ordered_at",
"parameters": [
{ "name": "start_date", "datatype": "date", "default": null }
]
},
"joins": [
{
"name": "customers",
"to": "analytics.sales.customers",
"sql": "o.customer_id = c.customer_id",
"cardinality": "many_to_one",
"origin": "declared"
}
],
"dimensions": [
{
"name": "order_month",
"kind": "time",
"sql": "DATE_TRUNC('month', o.ordered_at)",
"datatype": "date",
"description": "Month the order was placed"
},
{
"name": "customer_region",
"kind": "categorical",
"sql": "c.region",
"datatype": "string",
"filter_form": "in list",
"values": ["APAC", "EMEA", "NA"],
"required_join": "customers"
}
],
"examples": [
{
"source": "analyst",
"question": "What was average order value by month this year?",
"group_by": ["order_month"],
"parameters": { "start_date": "2026-01-01" },
"sql": "SELECT DATE_TRUNC('month', o.ordered_at) AS order_month, SUM(o.order_total) / COUNT(DISTINCT o.order_id) AS average_order_value FROM analytics.sales.orders o WHERE o.status = 'completed' AND o.order_total > 0 AND o.ordered_at >= '2026-01-01' GROUP BY 1 ORDER BY 1",
"result": {
"columns": ["order_month", "average_order_value"],
"row_count": 2,
"hash": "b41d07",
"executed_at": "2026-10-01T09:00:00Z",
"rows": [
["2026-01-01", "52.10"],
["2026-02-01", "54.80"]
]
}
}
],
"provenance": {
"source": "query_history",
"proposed_by": "data-team",
"execution_count": 412,
"distinct_analysts": 9
}
}
}
{
"name": "revenue_by_month_last_year",
"display_name": "What was revenue by month last year?",
"definition": {
"spec_version": "1.0-draft.1",
"question": "What was revenue by month last year?",
"paraphrases": [
"Monthly revenue for last year",
"Show last year's revenue per month"
],
"sql": "SELECT DATE_TRUNC('month', ordered_at) AS order_month, SUM(order_total) AS revenue FROM analytics.sales.orders WHERE status = 'completed' AND ordered_at >= :start_date AND ordered_at < :end_date GROUP BY 1 ORDER BY 1",
"dialect": "snowflake",
"parameters": [
{ "name": "start_date", "data_type": "date", "description": "First day of last year" },
{ "name": "end_date", "data_type": "date", "description": "First day of this year" }
],
"output_columns": [
{ "name": "order_month", "data_type": "date" },
{ "name": "revenue", "data_type": "decimal" }
],
"analysis": {
"tables": ["analytics.sales.orders"],
"columns": ["ordered_at", "order_total", "status"],
"dimensions": ["order_month"],
"measures": ["revenue"],
"filters": [{ "column": "status", "operator": "=", "value": "completed" }],
"extractor": "sqlglot 26.1"
},
"usage": {
"execution_count": 128,
"user_count": 7,
"last_executed_at": "2026-10-15T14:02:00Z"
},
"review_status": "verified",
"usage_note": "Counts completed orders only. For the amount per order, use the average_order_value metric."
}
}
Limits
| Limit | Value |
|---|---|
| Size of one definition | 1 MiB |
| Any single string or key | 256 KiB |
| Nesting depth | 32 levels |
| Values in one definition | 16,384 |
| Entries in one list or object | 1,024 |
| Characters | No NUL characters, anywhere |
| One bulk save | 32 definitions and 4 MiB of definitions |
| Saved query SQL | 64 KiB |
| Saved query question and each paraphrase | 1,000 characters |
| Paraphrases | 16 |
| Saved query usage note and parameter description | 4,000 characters |
Saved query names in parameters, output_columns, and analysis | 256 characters each |
| Studio import file | 1 MiB; up to 100 metrics or 1,000 query records |
| Studio release notes and withdrawal reason | 4,000 characters |
Errors
When a save is refused, the error names the field it’s about, for exampleField 'definition.source' is not valid. It never repeats the values or SQL you sent.
| Status | Meaning | What to do |
|---|---|---|
422 | The definition doesn’t fit the format. See the table below for each field. A metric whose calculation changed without a higher version is also refused here, at definition.version. | Fix the named field and save again. |
409 | Someone else saved at the same moment. | Reload the current revision, then save again. |
409 | The stored revision is in a format this save can’t build on. | Retrying won’t help. Contact your Atlan administrator. |
413 | A bulk save had more than 32 definitions or more than 4 MiB of definitions. | Split it into smaller batches. |
403 or 404 | You can’t edit this item, or it doesn’t exist. | Check the workspace and your role. |
503 | Atlan is busy, or couldn’t read the current revision in time. | Try again. |
422 fields:
| Field in the error | Why |
|---|---|
definition | An unknown field, a wrong type, or a size limit was exceeded. |
definition.spec_version | Not 1.0-draft.4 for a metric, or not 1.0-draft.1 for a saved query. |
definition.version | Not 1 or more, lower than the current version, or the calculation changed without raising it. |
definition.dialect, definition.formula, definition.aggregation.type, definition.output.alias, definition.output.datatype, definition.source.entity, definition.source.alias | Empty. |
definition.source | Not exactly one non-empty table or sql. |
definition.joins, definition.dimensions, definition.source.parameters | A name is empty or used twice. |
definition.dimensions.required_join | Names a join that isn’t in joins. |
definition.examples.group_by | Names a dimension that isn’t in dimensions. |
definition.examples.result.rows | A row has a different number of cells than columns. |
definition.sql | Saved query SQL is empty or over 64 KiB. |
definition.question, definition.paraphrases | Blank, too long, more than 16 paraphrases, or a paraphrase repeats the question or another paraphrase. |
definition.usage, definition.usage.last_executed_at | A count is too large, or the timestamp isn’t RFC 3339. |
Related
- How metrics work: What each part means and how versions differ.
- Write metrics: Fill in these fields in Studio.
- Import metrics and queries: Load many definitions from a file.