{"name":"dashboarding","url":"https://skills.sh/grafana/skills/dashboarding","install":"npx skills add grafana/skills --skill dashboarding","sdk":"grafana","key":"grafana/dashboarding","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.","hasContent":true,"content":"---\nname: dashboarding\nlicense: Apache-2.0\ndescription: 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.\n---\n\n# Grafana Dashboard Authoring\n\n> **Docs**: https://grafana.com/docs/grafana/latest/dashboards/\n\nDashboards are JSON. Author once, push via API, share by `uid`.\n\n## Prerequisites\n\n- Grafana stack (OSS, Enterprise, or Cloud) reachable from your machine\n- API token with `dashboards:write` (`Authorization: Bearer <token>`)\n- `jq` for inspecting responses\n- The JSON-schema cheat sheet in [`references/json-schema.md`](references/json-schema.md)\n\n## Common Workflows\n\n### 1. Push a new dashboard via the API + verify\n\n```bash\n# 1. Build the payload — wrap the dashboard JSON, set folder, mark overwrite\ncat > /tmp/dash.json <<'JSON'\n{\n  \"dashboard\": {\n    \"uid\": \"demo-svc-v1\",\n    \"title\": \"Demo Service\",\n    \"schemaVersion\": 41,\n    \"tags\": [\"demo\"],\n    \"time\": { \"from\": \"now-1h\", \"to\": \"now\" },\n    \"templating\": { \"list\": [] },\n    \"panels\": [{\n      \"id\": 1, \"type\": \"timeseries\", \"title\": \"Request Rate\",\n      \"gridPos\": { \"x\": 0, \"y\": 0, \"w\": 24, \"h\": 8 },\n      \"datasource\": { \"type\": \"prometheus\", \"uid\": \"prometheus\" },\n      \"targets\": [{\n        \"expr\": \"sum(rate(http_requests_total[5m])) by (status_code)\",\n        \"legendFormat\": \"{{status_code}}\", \"refId\": \"A\"\n      }],\n      \"fieldConfig\": { \"defaults\": { \"unit\": \"reqps\" }, \"overrides\": [] }\n    }]\n  },\n  \"folderUid\": \"\",\n  \"overwrite\": true,\n  \"message\": \"initial push\"\n}\nJSON\n\n# 2. Validate the JSON BEFORE you send it (catches trailing-comma typos)\njq empty /tmp/dash.json && echo \"json ok\"\n\n# 3. POST\nRESP=$(curl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  \"$GRAFANA/api/dashboards/db\" -d @/tmp/dash.json)\necho \"$RESP\" | jq '{status, uid, url, version}'\n# Expect: status=\"success\", url=\"/d/demo-svc-v1/...\", version=1 (incremented on each push)\n\n# 4. Verify the round-trip — read it back and confirm one panel + the expected title\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/dashboards/uid/demo-svc-v1\" \\\n  | jq '{title: .dashboard.title, panels: (.dashboard.panels | length)}'\n# Expect: {\"title\":\"Demo Service\",\"panels\":1}\n\n# 5. Open the dashboard in a browser — confirm the panel renders with data.\n```\n\n### 2. Add a `$job` template variable to an existing dashboard\n\n```bash\n# 1. Fetch existing dashboard\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/dashboards/uid/demo-svc-v1\" > /tmp/dash.json\n\n# 2. Edit templating.list — append:\n#   { \"name\":\"job\", \"type\":\"query\",\n#     \"datasource\":{\"type\":\"prometheus\",\"uid\":\"prometheus\"},\n#     \"query\":{\"query\":\"label_values(up, job)\",\"refId\":\"A\"},\n#     \"refresh\":2, \"includeAll\":true, \"multi\":true, \"label\":\"Service\" }\n#  (Use jq, an editor, or the Grafana UI — schema in references/json-schema.md.)\n\n# 3. Update the panel expr to use the variable: rate(http_requests_total{job=~\"$job\"}[5m])\n\n# 4. POST it back with overwrite: true. Verify the variable appears in the UI dropdown.\n```\n\n### 3. Compute an \"Error %\" column with a transformation\n\n```json\n{\n  \"id\": \"calculateField\",\n  \"options\": {\n    \"alias\": \"Error %\", \"mode\": \"reduceRow\",\n    \"reduce\": { \"reducer\": \"last\" },\n    \"binary\": { \"left\": \"errors\", \"right\": \"total\", \"operator\": \"/\" }\n  }\n}\n```\n\nAdd this to the panel's `transformations: []`. Verify in the UI panel inspector — the new field should appear and update with the variable selection.\n\nFull schema (panels, units, all transformations, annotations, links): [`references/json-schema.md`](references/json-schema.md).\n\n## API reference\n\n```bash\n# Get\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/dashboards/uid/<uid>\" | jq '.dashboard'\n\n# Search\ncurl -s -H \"Authorization: Bearer $TOKEN\" \\\n  \"$GRAFANA/api/search?query=kubernetes&type=dash-db\" | jq '.[] | {uid,title,folderTitle}'\n\n# Create folder\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \"$GRAFANA/api/folders\" \\\n  -d '{\"uid\":\"platform-team\",\"title\":\"Platform Team\"}'\n```\n\nFor dashboards embedded in app plugins, use `@grafana/scenes` (skill `grafana-o11y:grafana-scenes`).\n\n## Resources\n\n- [Dashboard JSON model](https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/view-dashboard-json-model/)\n- [HTTP API — dashboards](https://grafana.com/docs/grafana/latest/developers/http_api/dashboard/)\n- [Panel types](https://grafana.com/docs/grafana/latest/panels-visualizations/)\n- [Variables](https://grafana.com/docs/grafana/latest/dashboards/variables/)\n- [Transformations](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/transform-data/)\n","contentSource":"skills.sh/api/download/grafana/skills/dashboarding","contentFetchedAt":"2026-07-28T23:15:41.702Z"}