PluginBench
Skill
Pass
Audit score 90

dashboarding

grafana/skills

Build and ship Grafana dashboards as JSON via HTTP API with panels, variables, transformations, and annotations.

What is dashboarding?

This skill enables programmatic creation and modification of Grafana dashboards by working directly with the dashboard JSON model and HTTP API. Use it when you need to script dashboard creation, add template variables, apply transformations, or push dashboards via API—even when requests don't explicitly mention the API or schema.

  • Push new dashboards and update existing ones via POST /api/dashboards/db with verification
  • Configure panel types: timeseries, stat, gauge, table, heatmap, logs, traces, node-graph
  • Define template variables (query, multi-select, chained) with datasource bindings
  • Apply transformations: organize, calculateField, filterByValue to reshape data
  • Add dashboard and panel links with variable interpolation (${__field.labels.x}, ${__from})
  • Overlay Loki/Prometheus annotations and configure gridPos 24-column layout with units and thresholds

How to install dashboarding

npx skills add https://github.com/grafana/skills --skill dashboarding
Prerequisites
  • Grafana stack (OSS, Enterprise, or Cloud) reachable from your machine
  • API token with dashboards:write permission
  • jq for inspecting JSON responses
Claude Code
Cursor
Windsurf
Cline

How to use dashboarding

  1. 1.Fetch an existing dashboard or create new dashboard JSON with uid, title, schemaVersion, and panels array
  2. 2.Define datasources (Prometheus, Loki) and template variables in the templating.list section
  3. 3.Configure panels with gridPos layout, fieldConfig (units, thresholds), targets, and transformations
  4. 4.Validate JSON syntax with jq before sending
  5. 5.POST the dashboard payload to /api/dashboards/db with Authorization header and overwrite: true
  6. 6.Verify the response contains status=success and version number, then GET the dashboard UID to confirm round-trip

Use cases

Good for
  • Create a dashboard for a new service by writing and pushing dashboard JSON
  • Add a $job dropdown variable to filter metrics across multiple services
  • Compute an Error % column by chaining a calculateField transformation
  • Overlay deployment events as annotations on timeseries panels
  • Export and version-control dashboard JSON, then push updates via API
Who it's for
  • Platform engineers automating dashboard provisioning
  • SREs scripting observability infrastructure
  • DevOps teams managing dashboards as code
  • Backend developers building monitoring for new services

dashboarding FAQ

How do I add a template variable to filter by job?

Fetch the dashboard JSON, append an object to templating.list with name: 'job', type: 'query', datasource pointing to Prometheus, and query: 'label_values(up, job)'. Update panel expressions to use {job=~"$job"} and POST back with overwrite: true.

What's the gridPos layout system?

Grafana dashboards use a 24-column grid. Each panel has gridPos with x (0-23), y (row position), w (width 1-24), and h (height in grid units). Panels can overlap; y auto-increments as you add panels.

How do I verify a dashboard push succeeded?

Check the POST response for status: 'success', uid, url, and version fields. Then GET /api/dashboards/uid/{uid} and confirm the title and panel count match your payload.

Can I use transformations to compute new fields?

Yes. Add a calculateField transformation to the panel's transformations array with mode: 'reduceRow', a binary operator (/, *, +, -), and left/right field names. The new field appears in the panel output.

How do I overlay deployment events as annotations?

Add an annotations array to the dashboard JSON with datasource (Loki or Prometheus), query, and tagKeys. Use a logs panel or timeseries with annotation queries to show events like deploys on your metrics.

Full instructions (SKILL.md)

Source of truth, from grafana/skills.


name: dashboarding license: Apache-2.0 description: Build, modify, and ship Grafana dashboards as JSON via the HTTP API — panel types (timeseries / stat / gauge / table / heatmap / logs / traces / node-graph), gridPos 24-column layout, units, thresholds, template + datasource + chained variables, transformations (organize / calculateField / filterByValue), panel + dashboard links with ${__field.labels.x} / ${__from}, and Loki/Prometheus annotations. Use when scripting dashboard creation, writing the dashboard JSON for a new service, adding a $job dropdown variable, computing an "Error %" column with a transformation, overlaying deploys as annotations, or pushing a dashboard via POST /api/dashboards/db — even when the user says "create a dashboard for this metric", "add a service dropdown", "show errors as percentage", "overlay our deploys", or "export the dashboard JSON" without naming the API or schema. After every API push, verify with the returned version plus a GET on the dashboard UID.

Grafana Dashboard Authoring

Docs: https://grafana.com/docs/grafana/latest/dashboards/

Dashboards are JSON. Author once, push via API, share by uid.

Prerequisites

  • Grafana stack (OSS, Enterprise, or Cloud) reachable from your machine
  • API token with dashboards:write (Authorization: Bearer <token>)
  • jq for inspecting responses
  • The JSON-schema cheat sheet in references/json-schema.md

Common Workflows

1. Push a new dashboard via the API + verify

# 1. Build the payload — wrap the dashboard JSON, set folder, mark overwrite
cat > /tmp/dash.json <<'JSON'
{
  "dashboard": {
    "uid": "demo-svc-v1",
    "title": "Demo Service",
    "schemaVersion": 41,
    "tags": ["demo"],
    "time": { "from": "now-1h", "to": "now" },
    "templating": { "list": [] },
    "panels": [{
      "id": 1, "type": "timeseries", "title": "Request Rate",
      "gridPos": { "x": 0, "y": 0, "w": 24, "h": 8 },
      "datasource": { "type": "prometheus", "uid": "prometheus" },
      "targets": [{
        "expr": "sum(rate(http_requests_total[5m])) by (status_code)",
        "legendFormat": "{{status_code}}", "refId": "A"
      }],
      "fieldConfig": { "defaults": { "unit": "reqps" }, "overrides": [] }
    }]
  },
  "folderUid": "",
  "overwrite": true,
  "message": "initial push"
}
JSON

# 2. Validate the JSON BEFORE you send it (catches trailing-comma typos)
jq empty /tmp/dash.json && echo "json ok"

# 3. POST
RESP=$(curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "$GRAFANA/api/dashboards/db" -d @/tmp/dash.json)
echo "$RESP" | jq '{status, uid, url, version}'
# Expect: status="success", url="/d/demo-svc-v1/...", version=1 (incremented on each push)

# 4. Verify the round-trip — read it back and confirm one panel + the expected title
curl -s -H "Authorization: Bearer $TOKEN" \
  "$GRAFANA/api/dashboards/uid/demo-svc-v1" \
  | jq '{title: .dashboard.title, panels: (.dashboard.panels | length)}'
# Expect: {"title":"Demo Service","panels":1}

# 5. Open the dashboard in a browser — confirm the panel renders with data.

2. Add a $job template variable to an existing dashboard

# 1. Fetch existing dashboard
curl -s -H "Authorization: Bearer $TOKEN" \
  "$GRAFANA/api/dashboards/uid/demo-svc-v1" > /tmp/dash.json

# 2. Edit templating.list — append:
#   { "name":"job", "type":"query",
#     "datasource":{"type":"prometheus","uid":"prometheus"},
#     "query":{"query":"label_values(up, job)","refId":"A"},
#     "refresh":2, "includeAll":true, "multi":true, "label":"Service" }
#  (Use jq, an editor, or the Grafana UI — schema in references/json-schema.md.)

# 3. Update the panel expr to use the variable: rate(http_requests_total{job=~"$job"}[5m])

# 4. POST it back with overwrite: true. Verify the variable appears in the UI dropdown.

3. Compute an "Error %" column with a transformation

{
  "id": "calculateField",
  "options": {
    "alias": "Error %", "mode": "reduceRow",
    "reduce": { "reducer": "last" },
    "binary": { "left": "errors", "right": "total", "operator": "/" }
  }
}

Add this to the panel's transformations: []. Verify in the UI panel inspector — the new field should appear and update with the variable selection.

Full schema (panels, units, all transformations, annotations, links): references/json-schema.md.

API reference

# Get
curl -s -H "Authorization: Bearer $TOKEN" \
  "$GRAFANA/api/dashboards/uid/<uid>" | jq '.dashboard'

# Search
curl -s -H "Authorization: Bearer $TOKEN" \
  "$GRAFANA/api/search?query=kubernetes&type=dash-db" | jq '.[] | {uid,title,folderTitle}'

# Create folder
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" "$GRAFANA/api/folders" \
  -d '{"uid":"platform-team","title":"Platform Team"}'

For dashboards embedded in app plugins, use @grafana/scenes (skill grafana-o11y:grafana-scenes).

Resources