Dashboard YAML Templates
Uptrace dashboards can be defined as YAML templates. Templates are used for built-in dashboards that ship with Uptrace and for importing/exporting user-created dashboards.
When Uptrace receives new metrics, it checks available templates and automatically creates matching dashboards.
Template structure
Every template starts with a schema: v2 header followed by metadata, then the layout of the dashboard and optional metric_monitors.
schema: v2
name: 'Hostmetrics: Overview'
description: Tracks host CPU, memory, and system load.
tags: [otel, infra]
version: v26.11.05
setup_link: https://example.com/setup
doc_link: https://example.com/docs
# Optional: minimum query interval
min_interval: 1m
# Optional: shift the query time window
time_offset: 5m
# Optional: only apply when these metrics exist
metrics_match:
present:
- metric: system_cpu_utilization
- library: io.opentelemetry.instrumentation.system
metric: system_cpu_time
layout:
items: [] # the widgets or the groups of the dashboard
metric_monitors: [] # bundled alert monitors
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
schema | string | yes | Must be "v2" |
name | string | yes | Human-readable dashboard title |
description | string | no | Summary of the dashboard's purpose, shown in the template list |
tags | list | yes | Categorization labels (see Tags) |
version | string | yes | Revision in vYY.MM.DD format (e.g., v26.11.05) |
setup_link | string | no | URL to instrumentation/setup instructions |
doc_link | string | no | URL to documentation |
min_interval | duration | no | Minimum query interval (e.g., 1m, 5m) |
time_offset | duration | no | Shifts query time window (e.g., 5m) |
default_time_period | duration | no | Time period the dashboard shows when it opens without a stated range (e.g., 1h) |
tooltips_connected | bool | no | Whether a hover on one chart marks the same time on every chart. Defaults to true |
max_width | string | no | Page width: none (default), small, medium, large, or extra_large |
variables | list | no | Attribute names the filter bar of the dashboard offers as variables |
metrics_match | object | no | Metrics that must, or must not, exist before the template is applied (see Metric requirements) |
layout | object | no | The root of the layout (see Layout) |
metric_monitors | list | no | Metric monitors bundled with the template (see Metric monitors) |
Metrics and queries
Metrics and queries appear throughout the template (tables, grid items, monitors). They follow the same pattern everywhere.
Metrics
The metrics field declares metric aliases using MQL syntax:
metrics:
- system_cpu_utilization as $cpu_util
- system_memory_usage as $mem_usage
Each entry takes the form metric_name as $alias. The alias (prefixed with $) is used in queries.
Query
The query field is a list of MQL clauses. Splitting across lines improves readability -- clauses are joined into a single query during processing.
query:
- group by host_name
- avg($cpu_util) as cpu_avg
- sum($mem_usage{state="used"}) as mem_used
- where device !~ "loop"
Common clause patterns:
- Aggregations:
avg($x),sum($x),max($x),min($x),p50($x),p75($x),p90($x),p99($x) - Rate functions:
perMin(sum($x)),perSec(sum($x)) - Counting:
histogram_count($x),uniq($x, attr_name) - Grouping:
group by attr_name,group by attr1, attr2 - Filtering:
where attr = "value",where attr !~ "pattern" - Aliasing:
sum($x) as my_alias - Inline grouping:
avg($x) as y group by state - Attribute filtering:
$metric{state="used"},$metric{direction=read} - Arithmetic:
sum($a) / sum($b) as ratio
Layout
The layout key holds the root of the dashboard. The root and each group are a body: a list of items with the fields that arrange them. An item is a widget or a group, and its type selects which: omit it or state chart for a chart, a widget type for a widget of that type, or group for a group. A body holds widgets or groups, never both.
layout:
mode: tabs
items:
- type: group
title: CPU
items:
- title: CPU utilization
metrics:
- system_cpu_utilization as $cpu_util
query:
- avg($cpu_util)
- type: group
title: Memory
items:
- title: Memory utilization
metrics:
- system_memory_utilization as $mem_util
query:
- avg($mem_util)
Modes
The mode of a body states how it arranges its items:
| Mode | Holds | Description |
|---|---|---|
auto | widgets | A grid of columns. Each widget takes one cell, or the full width with full_width: true. All grid rows have one height |
custom | widgets | Each widget in the cell its grid_pos states, on a grid of 24 columns |
rows | groups | Groups one under another, each with a header that collapses it |
tabs | groups | Groups as tabs. The dashboard shows one group at a time |
Without mode, a body that holds groups is rows, a body whose widgets state grid_pos is custom, and any other body is auto. When a body that states no mode lists widgets beside groups, Uptrace puts each run of widgets in a group with no header. A rows or tabs body holds groups only, and Uptrace refuses a widget in it.
Body fields
| Field | Type | Description |
|---|---|---|
mode | string | auto, custom, rows, or tabs (see Modes) |
items | list | The widgets or the groups of the body, in the order the body shows them |
columns | int | Columns of an auto body, 1 to 12 |
column_width_mode | string | Narrowest column of an auto body: narrow, standard, wide, auto, or custom |
column_width | int | Narrowest column in pixels when column_width_mode is custom |
row_height_mode | string | Height of the grid rows of an auto body: short, standard, tall, or custom |
row_height | int | Grid row height in pixels when row_height_mode is custom |
fit_content | bool | Whether a widget that can fit its content grows or shrinks to it |
fit_min_height_mode | string | Least height of a widget that fits its content: none, short, standard, tall, or custom |
fit_min_height | int | Least height in pixels when fit_min_height_mode is custom |
fit_max_height_mode | string | Most height of a widget that fits its content: short, standard, tall, or custom |
fit_max_height | int | Most height in pixels when fit_max_height_mode is custom |
match_tallest | bool | Whether all widgets of a grid row take the height of the tallest one when fit_content is on |
Groups, rows and tabs
A group is an item with type: group. It is a body too, so it takes all the body fields, and it holds widgets or other groups. A group in a rows body is a row with a header, and a group in a tabs body is a tab.
- type: group
title: Gauges
columns: 6
column_width_mode: narrow
items:
- title: Availability
type: stat
metrics:
- httpcheck_status as $status
query:
- sum($status{http_status_class="2xx"}) / sum($status) as availability
columns:
availability: { unit: utilization }
| Field | Type | Required | Description |
|---|---|---|---|
type | string | yes | Always group |
title | string | no | Heading above the widgets. Omit it for a group with no heading |
description | string | no | Explanation shown below the heading |
collapsed | bool | no | Show the group closed when the dashboard loads. Only a group with a header can close |
hide_header | bool | no | Show no header. The group then only arranges its widgets |
items | list | yes | The widgets or the groups of the group |
Table widgets and linked grids
A table widget in the root can link a grid: a layout of its own that a row of the table opens, filtered to the group by values of that row. The grid key of the table widget holds it. It is a body, so it takes the same fields as layout.
layout:
items:
- type: table
title: Hosts
metrics:
- system_cpu_utilization as $cpu_util
- system_memory_usage as $mem_usage
query:
- group by host_name
- avg($cpu_util) as cpu_util
- sum($mem_usage{state="used"}) as mem_used
columns:
cpu_util: { unit: utilization }
mem_used: { unit: bytes }
grid_variables: [deployment_environment, service_name]
grid:
items:
- type: group
title: General
items:
- title: CPU utilization
metrics:
- system_cpu_utilization as $cpu_util
query:
- avg($cpu_util)
Only a table widget in the root links a grid. The grid keys of a table widget:
| Field | Type | Description |
|---|---|---|
grid | object | The linked grid. An empty mapping (grid: {}) links an empty grid |
grid_query | string | A where clause that each widget of the grid starts from, joined with the row a reader opened |
grid_variables | list | Attribute names the filter bar of the grid offers, beside the grouping attributes of the table |
grid_include | list | Other templates whose root items are appended to the grid (see Composition) |
See Table for the other fields of a table widget.
Widgets beside the table
The root can hold other widgets beside the table, for example a summary above it. They are ordinary widgets of the root:
layout:
items:
- title: Number of hosts
type: text
metrics:
- system_memory_usage as $mem_usage
query:
- uniq($mem_usage, host_name) as num_host
text: ${num_host} hosts
- type: table
title: Hosts
metrics:
- system_memory_usage as $mem_usage
query:
- group by host_name
- sum($mem_usage{state="used"}) as mem_used
Widget types
The type field of an item selects the widget. When type is omitted, the widget is a chart.
Common fields
All widget types share these fields:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Display heading. An empty title (title: "") shows the widget with none |
description | string | no | Explanation shown below the title |
type | string | no | One of: chart (default), table, stat, gauge, pie, heatmap, text |
full_width | bool | no | In an auto body, take the full width (true) or one cell (false). A table defaults to true, other types to false |
grid_pos | object | no | In a custom body, the cell on one line: {w: 12, h: 20, x: 0, y: 0}. A widget states grid_pos or full_width, not both |
height | string | no | In a custom body, content (fit the content) or fixed (the rows grid_pos states) |
Chart
Charts are the default grid item type. They render time-series data as line, bar, or scatter plots.
- title: CPU time
# type: chart (default, can be omitted)
metrics:
- system_cpu_time as $cpu_time
query:
- perMin(sum($cpu_time)) as cpu_time group by state
fill_opacity: 0.1
Chart-specific fields
| Field | Type | Description |
|---|---|---|
metrics | list | MQL metric expressions |
query | list | MQL query clauses |
chart | string | Chart type: line (default), bar, scatter |
tooltip | object | {mode, sort_order}: what the tooltip shows, and in which order |
sort_by | list | Columns the legend table sorts the series by |
max_data_points | int | Most datapoints the chart reads |
min_interval | duration | Lower bound for the grouping step |
fill_opacity | float | Area fill opacity, 0 to 1 |
stack | string | Stacking mode: "" (none) or "all" |
columns | map | Per-metric display settings with unit and color |
legend | object | Legend configuration (see below) |
properties | list | Visual properties (see Visual properties) |
overrides | list | Per-timeseries overrides (see Timeseries overrides) |
Legend configuration
legend:
type: table # "none", "list", or "table"
placement: bottom # "bottom" or "right"
values: [avg, min, max, last]
items_per_page: 10
Table
Table widgets show query results in rows with sortable columns.
- title: Slowest groups
type: table
metrics:
- uptrace_tracing_spans as $spans
query:
- group by _group_id
- group by _system
- p50($spans)
Table-specific fields
| Field | Type | Description |
|---|---|---|
metrics | list | MQL metric expressions |
query | list | MQL query clauses |
columns | map | Per-column display settings (see Column settings) |
overrides | list | Per-column visual property overrides (see Column overrides) |
items_per_page | int | Rows on one page of the table. Defaults to 5 |
compact_table | bool | Show the rows with less padding. Defaults to true |
lines_per_row | int | Lines of text one row shows. Defaults to 1 |
nulls_mode | string | How a cell with no value shows: keep, replace, or connect |
sort_by | list | Columns the table sorts its rows by |
grid, grid_query, grid_variables, grid_include | The linked grid (see Table widgets and linked grids) |
Column settings (shorthand)
The columns map provides a compact syntax for column formatting:
columns:
cpu_util: { unit: utilization }
mem_used: { unit: bytes, color: red }
availability: { unit: utilization, agg_func: avg }
max_latency: { unit: milliseconds, agg_func: max, display: bar }
Available column properties:
| Property | Description |
|---|---|
unit | Display unit (e.g., bytes, utilization, seconds, nanoseconds, milliseconds, 1, or custom like span/min) |
color | Display color |
agg_func | Aggregation function (e.g., sum, avg, max, last) |
display | Column display mode: value (default), sparkline, or bar. Can also be a map: {mode: bar, min: 0, max: 1} |
Column overrides (structured)
The overrides format provides more control:
overrides:
- column: cpu_util
properties:
- name: unit
value: utilization
- name: color
value: red
Stat
Stat widgets show a single aggregated value as text, optionally with value mappings for status labels.
- title: Status
type: stat
metrics:
- httpcheck_status as $status
query:
- sum($status{http_status_class="2xx"})
value_mappings:
- op: any
text: UNKNOWN
color: gray
- op: eq
value: 0
text: DOWN
color: red
- op: gte
value: 1
text: UP
color: green
Stat-specific fields
| Field | Type | Description |
|---|---|---|
metrics | list | MQL metric expressions |
query | list | MQL query clauses |
columns | map | Per-column settings with unit and agg_func |
overrides | list | Per-column visual property overrides |
value_mappings | list | Maps values to labels and colors |
Value mappings
Value mappings are evaluated in order, and the last matching rule wins, so a lower rule overrides the rules above it. Put the catch-all (any) first, and the more specific rules below it.
| Field | Type | Description |
|---|---|---|
op | string | Comparison operator: any, eq, lt, lte, gt, gte |
value | number | Threshold value (not required for any) |
text | string | Display label. An empty label keeps the number |
color | string | Display color |
Gauge
Gauges draw a single value on a dial, against the scale they state.
- title: CPU utilization
type: gauge
metrics:
- system_cpu_utilization as $cpu
query:
- avg($cpu) as cpu
columns:
cpu: { unit: utilization }
scale_min: 0
scale_max: 1
Gauge-specific fields
| Field | Type | Description |
|---|---|---|
metrics | list | MQL metric expressions |
query | list | MQL query clauses |
columns | map | Per-column settings with unit and agg_func |
overrides | list | Per-column visual property overrides |
value_mappings | list | Maps values to labels and colors (see Value mappings) |
scale_min | number | Value the dial starts at. Defaults to 0 |
scale_max | number | Value the dial ends at. Must be greater than scale_min |
shape | string | arc (default) or circle |
bar_cap | string | flat (default) or rounded |
bar_width_factor | number | Bar thickness as a fraction of the radius. Defaults to 0.3 |
sparkline | bool | Show a small trend chart beside the value |
Pie
Pie widgets show the share of each group, or of each column when the query has no grouping.
- title: Memory by state
type: pie
metrics:
- system_memory_usage as $mem
query:
- avg($mem) as mem
- group by state
columns:
mem: { unit: bytes }
Pie-specific fields
| Field | Type | Description |
|---|---|---|
metrics | list | MQL metric expressions |
query | list | MQL query clauses. With a grouping, state one value column |
columns | map | Per-column settings with unit and agg_func |
overrides | list | Per-column visual property overrides |
shape | string | donut (default) or pie |
slice_style | string | flat (default) or rounded |
slice_gap | bool | Part the slices with a small gap. Defaults to true |
color_scheme | string | default, carbon, sequential-reds, sequential-greens, or sequential-blues |
max_slices | int | Most slices the pie shows. Defaults to 8 |
other_slice | bool | Sum the smallest slices above max_slices into one slice named Other. Defaults to true |
legend | object | Legend configuration |
labels | object | Slice label configuration |
Heatmap
Heatmaps visualize the distribution of a single histogram metric over time.
- title: Span duration heatmap
type: heatmap
metric: uptrace_tracing_spans
unit: milliseconds
Heatmap-specific fields
| Field | Type | Description |
|---|---|---|
metric | string | Single metric name (not an alias) |
unit | string | Display unit |
query | list | Optional MQL query clauses for filtering |
Text
Text widgets render a Go template string with metric data, useful for summary counts and labels.
- title: Host count
type: text
metrics:
- process_runtime_go_goroutines as $goroutines
query:
- uniq($goroutines, host_name) as num_host
text: ${num_host} hosts
Text-specific fields
| Field | Type | Description |
|---|---|---|
metrics | list | MQL metric expressions |
query | list | MQL query clauses |
text | string | Template string using ${column_name} placeholders |
columns | map | Per-column settings with unit and agg_func |
overrides | list | Per-column visual property overrides |
Visual properties
Visual properties control chart appearance. They can be set via shorthand fields (chart, fill_opacity, stack) or the properties list.
properties:
- name: chartType
value: bar
- name: fillOpacity
value: 0.3
- name: stack
value: all
| Property | Type | Values |
|---|---|---|
chartType | string | line, bar, scatter |
stack | string | "" (off), all |
nullsMode | string | How a time bucket with no value is drawn: keep (a gap), replace (a zero), connect (a line across the gap) |
showPoints | string | When a line chart marks its points: auto, always, never |
lineWidth | number | Line thickness in pixels, 1 to 10 |
fillOpacity | number | 0 to 1 |
symbolSize | number | Point marker size in pixels, 1 to 20 |
symbol | string | Marker name, such as circle or triangle |
color | string | A CSS color |
colorScheme | string | Color scheme name |
colorMode | string | Which part of a stat is colored: none, value, backgroundGradient, backgroundSolid |
textSize | number | Stat value size in pixels, 1 to 200 |
unit | string | Display unit |
aggFunc | string | Aggregation function |
columnDisplay | object | {mode: value | sparkline | bar, min?, max?} |
nullsMode replaces the older boolean connectNulls.
Timeseries overrides
Chart widgets support per-timeseries overrides that apply visual properties to specific series:
overrides:
- matchers:
- target: metric # "metric" or "timeseries"
value: cpu_idle
properties:
- name: unit
value: utilization
- name: color
value: blue
The target field specifies what to match:
metric-- matches by metric/column nametimeseries-- matches by timeseries label
Metric monitors
The metric_monitors section bundles alert monitors with the dashboard. Each entry uses the same format as a metric monitor and adds a key:
metric_monitors:
- key: cpu_usage
name: CPU usage
type: threshold
metrics:
- system_cpu_load_average_15m as $load_avg_15m
- system_cpu_time as $cpu_time
query:
- avg($load_avg_15m) / uniq($cpu_time, cpu) as cpu_util
- group by host_name
column:
unit: utilization
max_value: 3
num_eval_points: 10
trend_agg_func: last
Monitor fields
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes | Unique monitor identifier within the template |
name | string | no | Human-readable title. Defaults to a name made from key |
type | string | yes | Detector: threshold, anomaly, outlier, or forecast |
metrics | list | yes | MQL metric expressions |
query | list | yes | MQL query clauses |
status | string | no | active (default) or paused |
column | string/object | no | Column to evaluate: a name, or {name: "col", unit: "ms"} |
resolution | duration | no | Data point interval |
num_eval_points | int | no | Number of recent data points to evaluate, 1 to 15 |
window_rule | string | no | at_all_times, at_least, on_average, or in_total (the last two for threshold only) |
min_breach_points | int | no | Number of points that must breach, for at_least |
absent_points | string | no | Missing data handling: zero, ignore, or alert |
time_offset | duration | no | Shifts the evaluation window, for late data |
trend_agg_func | string | no | Aggregation function for trend detection: sum, avg, median, last |
trend_sensitivity | string | no | Sensitivity of trend detection |
repeat_interval | object | no | Notification repeat interval configuration |
The detector settings sit at the top level beside type. A setting of another type is accepted and ignored.
| Type | Settings |
|---|---|
threshold | min_value, max_value (at least one), recovery: {min_value, max_value} |
anomaly | sensitivity, direction, seasonality, min_change, min_volume, preset |
outlier | sensitivity, direction, min_peers, min_change, keep_firing_for |
forecast | min_value, max_value (at least one), horizon, seasonality |
See Alerting for the meaning of each setting.
# Threshold with a recovery band inside the range
type: threshold
min_value: 100
max_value: 1000
recovery:
min_value: 110
max_value: 900
# Anomaly detection
type: anomaly
sensitivity: medium # very_low, low, medium, high, very_high
direction: both # both, above, below
min_change: 10 # optional: smallest move, in metric units
Older templates use a nested detector block (type: manual or type: auto). Uptrace still reads it and rewrites it to the current shape, but new templates should use the top-level type.
Template composition
A table widget can append the root items of other templates to its grid with grid_include. This enables modular dashboard composition:
# Parent: uptrace.dotnet.10.all.yml
schema: v2
name: '.NET: All'
tags: [otel, app]
version: v26.11.05
layout:
items:
- type: table
title: Services
metrics:
- process_runtime_dotnet_gc_heap_size as $heap_size
query:
- group by service_name
- sum($heap_size) as heap_size
grid_include:
- uptrace.dotnet.20.gc
- uptrace.dotnet.30.runtime
- uptrace.dotnet.40.thread_pool
Each entry references another template by filename (without .yml).
Metric requirements
The metrics_match field controls when a template is activated. It appears at the top level of the template:
metrics_match:
present:
- metric: system_cpu_utilization
- library: io.opentelemetry.instrumentation.system
metric: system_cpu_time
attrs: [cpu]
missing:
- metric: system_cpu_logical_count
present lists metrics the project must emit, and every entry must match. missing lists metrics the project must not emit. Each entry has these fields:
| Field | Type | Description |
|---|---|---|
metric | string or list | Metric name. A list matches any one of the names, for example after a rename |
library | string | Instrumentation library name (optional) |
attrs | list | Attribute keys the metric must carry (optional) |
A file can hold several YAML documents separated by ---. They are variants of the same dashboard for different metric sets, and Uptrace applies the first one whose metrics_match passes. Only the first document states the metadata (schema, name, tags, version, and so on). A variant without metrics_match matches every project, so it must be the last one. Older templates use require_metrics, which Uptrace still reads and rewrites to metrics_match.
Tags
Tags categorize dashboards for filtering. Use one data source tag and 1-3 category tags.
Data source tags
otel-- OpenTelemetry metricsprom-- Prometheus metrics
Category tags
infra-- System resources (CPU, RAM, disk, network)network-- Network-specific metricsdb-- Database systems (PostgreSQL, MySQL, Redis)app-- Application runtimes (Go, .NET, Java, JVM)k8s-- Kubernetes resourcestracing-- Distributed tracing and spanslogs-- Log aggregationmessaging-- Message queues (Kafka)self_monitoring-- Uptrace internal metrics (no data source tag needed)
tags: [otel, infra] # Host metrics
tags: [otel, app, db] # Go SQL client
tags: [otel, k8s, infra] # Kubernetes infrastructure
tags: [self_monitoring] # Uptrace self-monitoring
Template ID and filename
The template ID is derived from the filename:
uptrace.hostmetrics.10.overview.ymlbecomes IDuptrace.hostmetrics.overview- The numeric suffix (e.g.,
10) is stripped from the ID and used as a display priority
Validation
Templates are validated in two ways:
- YAML parsing with
DisallowUnknownFieldcatches typos and unknown keys. - JSON Schema validation against
schema.jsonensures structural correctness.
To validate templates:
go run -tags=cloud ./cmd/cloud dashboard validate_templates
Earlier template formats
Templates written for earlier releases still import. Uptrace rewrites each earlier spelling to the current one, and an export always writes the current format:
| Earlier spelling | Current spelling |
|---|---|
table at the top level | A table widget at the end of layout.items |
grid_sections (or grid_rows) | Groups in rows mode: in the grid of that table widget, or in the root when there is no table |
table_grid_items | Widgets in layout.items, before the table widget |
include_grid_sections, grid_query, grid_variables at the top level | grid_include, grid_query, grid_variables on the table widget |
type: gauge with no gauge field | type: stat |
require_metrics | metrics_match |
Older monitors with a nested detector block are rewritten too (see Metric monitors).
Full example
schema: v2
name: 'HTTP Check: Endpoints'
description: Monitors HTTP endpoint availability and response times.
tags: [otel, infra]
version: v26.11.05
setup_link: https://example.com/setup
layout:
fit_content: true
items:
- title: Successful checks
type: text
text: ${num_up} out of ${num_all}
metrics:
- httpcheck_status as $status
query:
- uniq($status{http_status_class="2xx"}) as num_all
- uniq($status{http_status_class="2xx"}) == 1 as num_up
- type: table
title: ""
metrics:
- httpcheck_status as $status
- httpcheck_duration as $duration
query:
- group by http_url
- group by host_name
- sum($status{http_status_class="2xx"}) / sum($status) as availability
- avg($duration)
columns:
availability: { unit: utilization }
grid:
items:
- type: group
title: Gauges
columns: 6
column_width_mode: narrow
items:
- title: Status
type: stat
metrics:
- httpcheck_status as $status
query:
- sum($status{http_status_class="2xx"})
value_mappings:
- op: any
text: UNKNOWN
color: gray
- op: eq
value: 0
text: DOWN
color: red
- op: gte
value: 1
text: UP
color: green
- type: group
title: General
items:
- title: HTTP check result
metrics:
- httpcheck_status as $status
query:
- $status group by http_status_code
- title: HTTP check duration
metrics:
- httpcheck_duration as $duration
query:
- avg($duration)
metric_monitors:
- key: http_check_is_down
name: HTTP check is down
metrics:
- httpcheck_status as $status
query:
- sum($status{http_status_class="2xx"}) as status_2xx
- group by http_url
- group by host_name
type: threshold
min_value: 1
max_value: 1
num_eval_points: 1
absent_points: alert
trend_agg_func: last