Grafana dashboards as code with JSON provisioning
Ryan Nakamura
Feb 2026
2 tabs
# Grafana provisioning: datasources
# /etc/grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
jsonData:
timeInterval: "15s"
httpMethod: POST
---
# Grafana provisioning: dashboards
# /etc/grafana/provisioning/dashboards/dashboards.yml
apiVersion: 1
providers:
- name: Default
orgId: 1
folder: ""
type: file
disableDeletion: false
editable: true
updateIntervalSeconds: 30
options:
path: /var/lib/grafana/dashboards
foldersFromFilesStructure: true
{
"dashboard": {
"title": "Application Overview",
"uid": "app-overview",
"timezone": "browser",
"refresh": "30s",
"time": {
"from": "now-1h",
"to": "now"
},
"templating": {
"list": [
{
"name": "service",
"type": "query",
"datasource": "Prometheus",
"query": "label_values(http_requests_total, service)",
"refresh": 2,
"multi": true,
"includeAll": true
},
{
"name": "environment",
"type": "custom",
"options": [
{"text": "production", "value": "production"},
{"text": "staging", "value": "staging"}
],
"current": {"text": "production", "value": "production"}
}
]
},
"panels": [
{
"title": "Request Rate",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"targets": [
{
"expr": "sum(rate(http_requests_total{service=~"$service"}[5m])) by (status_code)",
"legendFormat": "HTTP {{status_code}}"
}
],
"fieldConfig": {
"defaults": {
"unit": "reqps",
"custom": {
"drawStyle": "line",
"fillOpacity": 10
}
}
}
},
{
"title": "P95 Latency",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{service=~"$service"}[5m])) by (le))",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{service=~"$service"}[5m])) by (le))",
"legendFormat": "p99"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"thresholds": {
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 0.5},
{"color": "red", "value": 1.0}
]
}
}
}
},
{
"title": "Error Rate",
"type": "stat",
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 8},
"targets": [
{
"expr": "sum(rate(http_requests_total{status=~"5..", service=~"$service"}[5m])) / sum(rate(http_requests_total{service=~"$service"}[5m])) * 100"
}
],
"fieldConfig": {
"defaults": {
"unit": "percent",
"thresholds": {
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 1},
{"color": "red", "value": 5}
]
}
}
}
}
]
}
}
2 files · yaml, json
Explain with highlit
Grafana visualizes Prometheus metrics through configurable dashboards. Dashboard JSON models define panels, queries, and layouts programmatically. Panel types include timeseries for graphs, stat for single values, table for tabular data, and gauge for thresholds. PromQL queries power panel data with rate(), sum(), and histogram_quantile(). Variables (template variables) enable dynamic filtering by service, environment, or instance. Row grouping organizes related panels. Alert thresholds add visual indicators. Dashboard provisioning from YAML auto-loads dashboards at startup. Grafana as code enables version-controlled, reproducible dashboards. Annotations mark deployments on graphs. Link panels to drill-down dashboards for investigation.