---
title: "Template annotations and labels | Grafana Plugins documentation"
description: "Use Go templating in rule annotations and labels so each alert describes its own labels and value, with the variables and functions the ruler makes available at evaluation time."
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# Template annotations and labels

Annotation and label values are Go templates, rendered by the ruler each time the rule is evaluated. This is what lets one rule produce alerts that describe their own specifics.

## Available variables

Expand table

| Variable                | Contains                                                    |
|-------------------------|-------------------------------------------------------------|
| `{{ $labels }}`         | The labels of this alert instance                           |
| `{{ $value }}`          | The numeric value the expression returned for this instance |
| `{{ $externalLabels }}` | The external labels configured on the ruler                 |

The scope is one alert instance. A rule matching fifty filesystems renders its annotations fifty times, once per instance, each with that instance’s own labels and value.

## Common patterns

Reference a label by name:

Go ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```go
{{ $labels.instance }} is unreachable.
```

Format the value, which is a float and prints unhelpfully by default:

Go ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```go
Disk is {{ $value | printf "%.1f" }}% full.
```

Use `humanize` for large or small numbers, and `humanizeDuration` for seconds:

Go ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```go
Receiving {{ $value | humanize }} requests per second.
Backlog will clear in {{ $value | humanizeDuration }}.
```

Build a link that points at the specific thing that’s broken:

Go ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```go
https://grafana.example.com/d/abc123?var-instance={{ $labels.instance }}
```

## A worked example

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
annotations:
  summary: 'Disk almost full on {{ $labels.instance }}'
  description: >-
    {{ $labels.mountpoint }} on {{ $labels.instance }} is
    {{ $value | printf "%.1f" }}% full and needs attention.
  runbook_url: https://runbooks.example.com/disk-full
```

The `summary` is short enough to work as a notification title. The `description` carries the detail. The `runbook_url` is static, which is fine. Not every annotation has to be templated.

## Templating labels

Labels can be templated too, but it’s usually a mistake. A label whose value changes while the alert is firing changes the alert’s identity, which Alertmanager reads as the old alert resolving and a new one starting, re-notifying people mid-incident.

Templating a label from another label is safe, since neither changes. Templating a label from `$value` is not.

## Keep it simple

These templates run on every evaluation of every instance, so they’re not the place for elaborate logic. If a notification needs a complicated layout, build that in a notification template instead, where it runs once per notification rather than once per instance per evaluation. Refer to [Templates](/docs/plugins/grafana-prometheusalerting-app/latest/fundamentals/templates/).

## Troubleshooting

A template that fails to parse makes the rule fail to evaluate. The rule shows **error** health and its **Last Error** carries the reason, so a rule that goes quiet right after an annotation edit is usually a broken template.

Use **Query Preview** in the rule editor to check which labels are actually available before referencing them. `{{ $labels.pod }}` renders as nothing at all if the series has no `pod` label.
