Grafana Dashboard JSON Model
Every Grafana dashboard is stored internally as a JSON document. When you click Save on a dashboard, Grafana writes this JSON to its database. Understanding the JSON model lets you edit dashboards programmatically, version-control them in Git, automate dashboard creation, and diagnose problems that the UI cannot fix.
The Blueprint Analogy
A JSON dashboard file is like an architectural blueprint. An architect draws plans; a builder constructs the physical building from those plans. You write or edit the JSON; Grafana constructs the visual dashboard from that document. Two identical JSON files produce two identical dashboards on any Grafana instance.
Viewing the JSON Model
Open any dashboard. Click the Share button → Export tab → View JSON. The full JSON document for the current dashboard appears. You can copy it, edit it, and import it back. Alternatively, open dashboard settings (gear icon) → JSON Model tab to see and directly edit the dashboard JSON inside the UI.
Top-Level Structure
{
"id": 42,
"uid": "abc123xyz",
"title": "Server Health Overview",
"description": "CPU, memory, disk, and network for all servers",
"tags": ["servers", "infrastructure"],
"timezone": "browser",
"refresh": "30s",
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"schemaVersion": 38,
"version": 7,
"panels": [ ... ],
"templating": { "list": [ ... ] },
"annotations": { "list": [ ... ] },
"links": [ ... ]
}
id and uid
The id is a numeric identifier assigned by the Grafana database. The uid is a short alphanumeric string that uniquely identifies the dashboard. The UID appears in the dashboard URL. When exporting for sharing, set the UID explicitly so imported dashboards have a predictable URL.
schemaVersion
The schemaVersion field tells Grafana which version of the JSON schema this dashboard uses. Grafana migrates older schemas automatically on import. Leave this at the current version Grafana writes — do not change it manually.
version
The version number increments each time you save the dashboard. Grafana keeps a history of saved versions. Go to dashboard settings → Versions to see the history and restore a previous version.
Panel Object Structure
The panels array contains one object per panel. Each object defines the panel's type, position, size, queries, and display options.
{
"id": 1,
"type": "timeseries",
"title": "CPU Usage (%)",
"description": "Average CPU across all cores",
"gridPos": {
"x": 0,
"y": 0,
"w": 12,
"h": 8
},
"datasource": {
"type": "prometheus",
"uid": "prometheus-ds"
},
"targets": [
{
"refId": "A",
"expr": "100 - (avg by(instance)(rate(node_cpu_seconds_total{mode=\"idle\"}[5m]))*100)",
"legendFormat": "{{instance}}"
}
],
"options": { ... },
"fieldConfig": { ... }
}
gridPos – Position and Size
The gridPos object places the panel on the 24-column dashboard grid.
x: column position (0 to 23) y: row position (0 = top, increases downward) w: width in columns (1 to 24) h: height in rows (each row unit ≈ 30 pixels) Example: full-width panel, 8 rows tall, at top left x: 0, y: 0, w: 24, h: 8 Example: half-width panel, second position on row 0 x: 12, y: 0, w: 12, h: 8
targets – Queries
The targets array holds the queries for this panel. Each target is one query (Query A, B, C…). The refId field sets the label — "A", "B", etc.
fieldConfig – Display Options
The fieldConfig object controls how values are displayed — units, thresholds, colour mapping, and overrides for individual series.
"fieldConfig": {
"defaults": {
"unit": "percent",
"min": 0,
"max": 100,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 70 },
{ "color": "red", "value": 90 }
]
}
},
"overrides": []
}
Templating – Variables in JSON
Dashboard variables are stored in the templating.list array. Each variable object defines its type, query, and default value.
"templating": {
"list": [
{
"name": "instance",
"label": "Server",
"type": "query",
"datasource": { "type": "prometheus", "uid": "prometheus-ds" },
"query": "label_values(up, instance)",
"multi": true,
"includeAll": true,
"current": { "text": "All", "value": "$__all" }
}
]
}
Row Panels
Dashboard rows are also panel objects with "type": "row". They sit in the panels array like regular panels but act as collapsible group headers.
{
"type": "row",
"title": "CPU Metrics",
"collapsed": false,
"gridPos": { "x": 0, "y": 0, "w": 24, "h": 1 },
"panels": []
}
Editing the JSON Model Directly
In Dashboard Settings → JSON Model, paste modified JSON and click Save changes. Grafana immediately applies the changes. This method is faster than navigating through the UI for bulk edits — for example, changing the data source UID in all 20 panels at once by doing a find-and-replace in the JSON text.
Version-Controlling Dashboards with Git
Store dashboard JSON files in a Git repository alongside your application code. Treat every dashboard as code — review changes in pull requests, roll back to previous versions with git revert, and deploy dashboards automatically via CI/CD pipelines using the Grafana API.
Git workflow:
git repo/
└── grafana/
└── dashboards/
├── server-health.json
├── kubernetes-overview.json
└── business-metrics.json
Update a dashboard:
1. Export JSON from Grafana
2. git add server-health.json
3. git commit -m "Add disk I/O panel to server health dashboard"
4. git push
5. CI/CD pipeline calls Grafana API to import updated JSON
Creating a Dashboard via API
POST http://localhost:3000/api/dashboards/db
Authorization: Bearer <API_TOKEN>
Content-Type: application/json
{
"dashboard": { ... JSON model ... },
"folderId": 0,
"overwrite": true,
"message": "Added disk panel"
}
The overwrite: true flag updates an existing dashboard with the same UID. Without it, Grafana returns an error if a dashboard with that UID already exists.
