Grafana Dashboard Authoring
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>) jqfor inspecting responses- The JSON-schema cheat sheet in
references/json-schema.md
Common Workflows
1. Push a new dashboard via the API + verify
bash# 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
bash# 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
json{ "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
bash# 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).


