Dashboard JSON model, export and versions

Grafana · Advanced · 10 min

Everything the UI does ends up in this JSON; reading it is the step from clicking dashboards to reviewing, generating and versioning them.

Every dashboard is one JSON document, visible under Edit, Settings, JSON Model. The important fields:

  • uid: the stable identifier used in URLs (/d/<uid>/<slug>) and links. id is a per-instance database number; it is ignored on import and should be null in files.
  • title, tags, timezone, time (default range), refresh, graphTooltip.
  • templating.list: the variables, each with query, datasource, multi, includeAll, current.
  • annotations.list and links.
  • panels[]: each with type, gridPos, datasource ({"type": "prometheus", "uid": "prom-main"}), targets (queries), fieldConfig.defaults and overrides, options, and transformations. Rows are panels of type row holding collapsed panels.
  • schemaVersion and version: Grafana migrates old schemas on load; the version number increases with every save.

Export (Share, Export) offers the raw model or Export for sharing externally, which replaces concrete data source UIDs with placeholders like ${DS_PROMETHEUS} listed under __inputs. On Import (Dashboards, New, Import) the user maps each input to a local data source, and that is how dashboards from grafana.com/dashboards, where every published dashboard has a numeric id, work across installations.

Versions (Settings, Versions) lists every save with author and message, lets you compare two versions as a JSON diff, and restore an older one, which creates a new version rather than rewriting history. Provisioned dashboards keep their history too but are overwritten from the file.

Grafana 12 adds a v2 schema and a Kubernetes-style dashboards API (dashboard.grafana.app), used by the new layouts and Git Sync; the classic model above remains supported and is still what most tooling emits.

Example

{
  "uid": "api-overview",
  "id": null,
  "title": "API overview",
  "tags": ["api", "service"],
  "timezone": "browser",
  "schemaVersion": 41,
  "version": 17,
  "time": {"from": "now-6h", "to": "now"},
  "refresh": "1m",
  "graphTooltip": 1,
  "templating": {"list": [{
    "name": "job", "type": "query", "query": "label_values(up, job)",
    "datasource": {"type": "prometheus", "uid": "${DS_PROMETHEUS}"},
    "refresh": 2, "multi": false, "includeAll": false}]},
  "__inputs": [{"name": "DS_PROMETHEUS", "type": "datasource",
                "pluginId": "prometheus", "label": "Prometheus"}],
  "panels": [{
    "id": 1, "type": "timeseries", "title": "Requests",
    "gridPos": {"x": 0, "y": 0, "w": 12, "h": 8},
    "datasource": {"type": "prometheus", "uid": "${DS_PROMETHEUS}"},
    "targets": [{"refId": "A", "expr": "sum(rate(http_requests_total{job=\"$job\"}[$__rate_interval]))"}],
    "fieldConfig": {"defaults": {"unit": "reqps"}, "overrides": []},
    "options": {}
  }]
}

Remember

  • uid is stable and used in URLs; id is instance-local and should be null in files
  • Export for sharing externally replaces data sources with ${DS_*} inputs mapped on import
  • Versions can be compared as a JSON diff and restored

Watch out for

  • Copying a dashboard JSON between instances with concrete data source uids that don't exist there, so every panel shows "datasource not found".

Check yourself

  1. What does "Export for sharing externally" change in the JSON?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: grafana.com/docs/grafana/latest/dashboards/build-dashboards/view-dashboard-json-model/