Create, configure, and provision Grafana dashboards and visualizations. Use when: building Grafana dashboards, configuring panels (time series, stat, gauge, table, heatmap, logs, geomap, bar chart), writing PromQL/LogQL queries for Grafana panels, setting up Grafana variables and templating, configuring Grafana annotations, creating Grafana alert rules with contact points and notification policies, provisioning dashboards via YAML/JSON, using Grafonnet jsonnet library or Terraform grafana provider for dashboard-as-code, organizing Grafana folders and permissions. Do NOT use when: configuring Prometheus server without Grafana involvement, building Datadog or New Relic dashboards, creating Kibana/OpenSearch visualizations, general metrics collection or instrumentation without dashboard context, configuring standalone alertmanager without Grafana unified alerting.
Every Grafana dashboard is a JSON document. Set id: null for new dashboards; Grafana assigns it.
{
"id": null,
"uid": "svc-overview-01",
"title": "Service Overview",
"tags": ["production", "backend"],
"timezone": "browser",
"editable": true,
"graphTooltip": 1,
"schemaVersion": 39,
"version": 0,
"time": { "from": "now-6h", "to": "now" },
"refresh": "30s",
"panels": [],
"templating": { "list": [] },
"annotations": { "list": [] },
"links": []
}
Key fields: uid (unique string, stable across exports), schemaVersion (39+ for Grafana 11.x), graphTooltip (0=default, 1=shared crosshair, 2=shared tooltip).
Every panel requires gridPos: { "x": 0, "y": 0, "w": 12, "h": 8 }. Dashboard width is 24 units.
{
"type": "timeseries",
"title": "Request Rate",
"gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 },
"datasource": { "type": "prometheus", "uid": "prometheus-main" },
"targets": [{
"expr": "sum(rate(http_requests_total{job=\"$job\"}[5m])) by (status_code)",
"legendFormat": "{{status_code}}"
}],
"fieldConfig": {
"defaults": {
"unit": "reqps",
"custom": { "drawStyle": "line", "fillOpacity": 10, "lineWidth": 2 }
},
"overrides": [{
"matcher": { "id": "byName", "options": "500" },
"properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }]
}]
}
}
{
"type": "stat",
"title": "Total Requests",
"targets": [{ "expr": "sum(increase(http_requests_total{job=\"$job\"}[24h]))" }],
"fieldConfig": {
"defaults": {
"unit": "short",
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 10000 },
{ "color": "red", "value": 50000 }
]
}
}
},
"options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" }
}
Set options.showThresholdLabels: true and fieldConfig.defaults.min/max for proper scaling. Use unit field for display (percent, bytes, etc.).
{
"type": "table",
"title": "Top Endpoints",
"targets": [{
"expr": "topk(10, sum(rate(http_requests_total[5m])) by (handler))",
"format": "table", "instant": true
}],
"transformations": [
{ "id": "organize", "options": { "excludeByName": { "Time": true } } }
],
"fieldConfig": {
"overrides": [{
"matcher": { "id": "byName", "options": "Value" },
"properties": [{ "id": "custom.cellOptions", "value": { "type": "color-background" } }]
}]
}
}
{
"type": "logs",
"title": "Application Logs",
"datasource": { "type": "loki", "uid": "loki-main" },
"targets": [{
"expr": "{namespace=\"$namespace\", app=\"$app\"} |= \"$search\" | logfmt | level=~\"$level\"",
"refId": "A"
}],
"options": { "showTime": true, "sortOrder": "Descending", "wrapLogMessage": true }
}
"type": "heatmap". Set options.calculate: true for raw data, false for pre-bucketed. Configure options.yAxis.unit and color.scheme."type": "barchart". Set options.orientation ("horizontal"/"vertical"), options.showValue. Pair with instant queries and table format."type": "geomap". Requires latitude/longitude fields or field mappings. Set options.view.id for map type.# Rate of counter
rate(http_requests_total{job="$job"}[$__rate_interval])
# Error ratio
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
# Histogram quantile (p99 latency)
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{job="$job"}[5m])) by (le))
# Aggregation with variable
sum by ($groupby) (rate(metric_name[$__rate_interval]))
Use $__rate_interval instead of hardcoded [5m] — it auto-adjusts to scrape interval. Use $__interval for non-rate aggregations.
# Filter and parse
{namespace="production", app="api"} |= "error" | json | line_format "{{.message}}"
# Metric query from logs (rate of errors)
sum(rate({app="api"} |= "error" [5m])) by (level)
# Pattern-based extraction
{job="nginx"} | pattern "<ip> - - <_> \"<method> <uri> <_>\" <status> <size>" | status >= 400
Define in templating.list. Variable types:
{
"name": "namespace",
"type": "query",
"datasource": { "type": "prometheus", "uid": "prometheus-main" },
"query": "label_values(kube_pod_info, namespace)",
"refresh": 2,
"sort": 1,
"multi": true,
"includeAll": true,
"allValue": ".*"
}
refresh: 1=on dashboard load, 2=on time range change. sort: 0=disabled, 1=alpha asc, 2=alpha desc, 3=numeric asc.
Create dependency chains: namespace → service → pod.
[
{ "name": "namespace", "query": "label_values(kube_pod_info, namespace)" },
{ "name": "service", "query": "label_values(kube_pod_info{namespace=\"$namespace\"}, service)" },
{ "name": "pod", "query": "label_values(kube_pod_info{namespace=\"$namespace\", service=\"$service\"}, pod)" }
]
{ "name": "env", "type": "custom", "query": "production,staging,development", "current": { "text": "production", "value": "production" } }
{ "name": "smoothing", "type": "interval", "query": "1m,5m,15m,30m,1h", "auto": true, "auto_count": 30, "auto_min": "10s" }
{ "name": "ds_prometheus", "type": "datasource", "query": "prometheus" }
Reference in panels: "datasource": { "type": "prometheus", "uid": "$ds_prometheus" }.
Use $var for simple substitution, ${var} mid-string, ${var:regex} for regex-escaped, ${var:pipe} for pipe-delimited multi-values, ${var:csv} for comma-separated.
{
"annotations": {
"list": [{
"name": "Deployments",
"datasource": { "type": "prometheus", "uid": "prometheus-main" },
"expr": "changes(deploy_timestamp{app=\"$app\"}[1m]) > 0",
"tagKeys": "app,version",
"textFormat": "Deployed {{version}}",
"iconColor": "blue",
"enable": true
}]
}
}
{
"links": [
{ "title": "Logs", "url": "/d/logs-dash/logs?var-app=$app", "type": "link", "icon": "doc", "targetBlank": false },
{ "title": "Related", "type": "dashboards", "tags": ["production"], "asDropdown": true }
]
}
Place in provisioning/dashboards/. Set foldersFromFilesStructure: true to mirror subdirectory layout as Grafana folders. Set allowUiUpdates: false to enforce file-based source of truth.
apiVersion: 1