Skip to content
DevOps AI ToolKit
Newsletter
All prompts
AI for Grafana Difficulty: Advanced ClaudeChatGPT

Grafana Terraform Provider Dashboards Prompt

Manage Grafana dashboards, folders, and alerts as code using the Terraform grafana provider with stable UIDs and state.

Target user
Platform engineers running Grafana in a Terraform workflow
Difficulty
Advanced
Tools
Claude, ChatGPT

The prompt

You are a senior platform engineer who manages Grafana with the Terraform `grafana/grafana` provider — dashboards, folders, data sources, alert rules, and contact points all in HCL.

I will provide:
- The resources to manage (folders, dashboards, alerts)
- The Grafana URL/auth and whether it is Cloud or self-hosted
- Existing dashboards to import vs greenfield

Your job:

1. **Provider setup**: configure `provider "grafana"` with `url` and `auth` (service account token), pin the provider version, and store state remotely (locked).
2. **Folders first**: create `grafana_folder` resources and reference `.id`/`.uid` from dashboards so ordering is correct.
3. **Dashboards**: use `grafana_dashboard` with `config_json`; keep the JSON in external files via `file()` or `jsonencode()`, and let the provider manage the `uid`.
4. **Avoid drift**: strip server-managed fields (`id`, `version`) from imported JSON; the provider re-adds them. Use `overwrite = true` cautiously.
5. **Alerts**: model `grafana_rule_group`, `grafana_contact_point`, `grafana_notification_policy`, and `grafana_mute_timing` rather than clicking them.
6. **Data sources**: define `grafana_data_source` with `secure_json_data_encoded` for secrets pulled from Vault/SSM, never hardcoded.
7. **Import existing**: use `terraform import grafana_dashboard.x {folderUID}:{uid}` and reconcile the JSON before the first apply.
8. **CI plan gate**: run `terraform plan` in PRs so dashboard diffs are reviewed; apply only on merge.

Mark DESTRUCTIVE: `terraform destroy` or removing a resource block (deletes the dashboard/folder), changing a `uid`, or `overwrite = true` clobbering UI edits.

---

Resources to manage: [DESCRIBE]
Grafana URL/auth: [DESCRIBE]
Import vs greenfield: [DESCRIBE]

Why this prompt works

The Terraform grafana provider spans dozens of resource types, and the common failures — perpetual drift from server-managed JSON, accidental deletes when a block is removed, secrets in HCL — are predictable. This prompt front-loads folder ordering, uid stability, secret sourcing, and a plan-review gate so dashboards-as-code stays reviewable and non-destructive.

How to use it

  1. Decide import vs greenfield so the JSON reconciliation step is planned.
  2. Provide auth details to configure the provider and secret backend.
  3. Run plan in CI and review the dashboard diff before merge.
  4. Never edit managed dashboards in the UI unless you accept clobbering.

Useful commands

# Import an existing dashboard into state
terraform import grafana_dashboard.slo "general:slo-overview"

# Plan / apply with the Grafana provider
export GRAFANA_URL=https://grafana.example.com
export GRAFANA_AUTH=$GRAFANA_SA_TOKEN
terraform plan -out plan.tfplan
terraform apply plan.tfplan

# Verify the resulting dashboard via API
curl -s -H "Authorization: Bearer $GRAFANA_AUTH" \
  "$GRAFANA_URL/api/dashboards/uid/slo-overview" | jq '.dashboard.title'

Example config

terraform {
  required_providers {
    grafana = { source = "grafana/grafana", version = "~> 3.0" }
  }
}

provider "grafana" {
  url  = var.grafana_url
  auth = var.grafana_sa_token   # from Vault/SSM, not literal
}

resource "grafana_folder" "slo" {
  title = "SLO Dashboards"
  uid   = "slo"
}

resource "grafana_dashboard" "slo_overview" {
  folder      = grafana_folder.slo.uid
  config_json = jsonencode({
    uid   = "slo-overview"
    title = "SLO Overview"
    panels = [{
      title = "Availability"
      type  = "timeseries"
      datasource = { type = "prometheus", uid = "prometheus-prod" }
      targets = [{ expr = "1 - (sum(rate(errors[5m])) / sum(rate(total[5m])))" }]
    }]
    schemaVersion = 39
    time = { from = "now-6h", to = "now" }
  })
}

resource "grafana_contact_point" "slack" {
  name = "slack-critical"
  slack {
    url       = var.slack_webhook   # secret
    recipient = "#alerts-critical"
  }
}

Common findings this catches

  • Perpetual diffsid/version not stripped from JSON.
  • Accidental deletes → removed block deletes the real object.
  • Broken referencesuid changed after alerts/links wired.
  • Secrets in state → tokens hardcoded instead of variables.
  • Unreviewed dashboard changes → no plan gate in CI.
  • Clobbered UI editsoverwrite = true on a hand-edited dashboard.

When to escalate

  • Migrating hundreds of hand-built dashboards — staged import plan.
  • Shared state across many teams — workspace and RBAC design.
  • Provider major-version upgrades with breaking schema — platform owner.

Related prompts

Newsletter

Free: the DevOps AI Incident-Triage Cheat Sheet

Subscribe and we’ll send you the one-page cheat sheet — plus weekly AI prompts, automation ideas, and tool reviews for infrastructure engineers. One email a week. No spam, unsubscribe anytime.

  • AI Incident-Triage Cheat Sheet (PDF)
  • Access to 2,104 DevOps AI prompts
  • One practical workflow email per week