grafana/skills

datasources-provisioning

Generate a copy-paste Grafana data source provisioning file (YAML or Terraform) for any plugin from its standardized settings schema on the plugins CDN.

View source
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Workflow

1. Ask the starting point: from scratch, or from an existing data source?

Ask this before anything else (skip only if the user already made it clear):

  • From scratch — the user names a plugin type to provision → continue with step 2.
  • From an existing data source in a running instance → jump to Convert an existing data source, then return to step 6.

2. Resolve the full plugin id

Provisioning needs the canonical plugin id (<org>-<name>-datasource), not the short name a user might say.

  • Already canonical (contains -datasource or -app)? Use as-is: yesoreyeram-infinity-datasource.
  • Short name only (e.g. infinity, clickhouse)? Search the catalog API with filter=<keyword>:
bash
  curl -s "https://grafana.com/api/plugins?filter=infinity" \
    | jq -r '.items[] | "\(.slug)\t\(.name)"'
  # → yesoreyeram-infinity-datasource    Infinity

Multiple matches → show the candidates and ask which one.

The snippets below use Infinity (yesoreyeram-infinity-datasource) as the worked example — substitute the id resolved here (and the version from step 3) in every command and output.

3. Resolve the latest version

bash
curl -s "https://grafana.com/api/plugins/yesoreyeram-infinity-datasource" | jq -r '.version'

Never hardcode a version — the CDN path is version-pinned and a stale version 404s.

4. Fetch the settings schema (primary structured source)

https://plugins-cdn.grafana.net/<PLUGIN_ID>/<VERSION>/public/plugins/<PLUGIN_ID>/schema/dsconfig.json
bash
ID=yesoreyeram-infinity-datasource
VER=$(curl -s "https://grafana.com/api/plugins/$ID" | jq -r '.version')
curl -sf "https://plugins-cdn.grafana.net/$ID/$VER/public/plugins/$ID/schema/dsconfig.json"

This file conforms to the dsconfig schema spec — the source of truth for how to interpret it. Don't re-derive field semantics from memory (valueType alone spans string, number, boolean, array, object, map, any); consult the spec when a field isn't a plain scalar:

  • Prose spec: https://raw.githubusercontent.com/grafana/dsconfig/refs/heads/main/dsconfig/schema.md
  • Meta-schema (defines the format of every dsconfig.json): https://raw.githubusercontent.com/grafana/dsconfig/refs/heads/main/dsconfig/schema.json

What you need from each field to provision: key (the provisioning key), valueType, target (root | jsonData | secureJsonData), and validations (honor allowedValues for selectors like auth_method). Orientation example (schemaVersion: "v1"):

json
{
  "pluginType": "yesoreyeram-infinity-datasource",
  "fields": [
    {
      "key": "auth_method",
      "valueType": "string",
      "target": "jsonData",
      "validations": [
        {
          "type": "allowedValues",
          "values": [
            "none",
            "basicAuth",
            "apiKey",
            "bearerToken",
            "oauth2",
            "aws",
            "azureBlob"
          ]
        }
      ]
    }
  ]
}

Select only the fields relevant to what the user asked for (chosen auth method + connection), not all of them. Each field's description tells you which auth method it belongs to.

For ready-made example configs, fetch v0alpha1.json:

https://plugins-cdn.grafana.net/<PLUGIN_ID>/<VERSION>/public/plugins/<PLUGIN_ID>/schema/v0alpha1.json
bash
ID=yesoreyeram-infinity-datasource
VER=$(curl -s "https://grafana.com/api/plugins/$ID" | jq -r '.version')
curl -sf "https://plugins-cdn.grafana.net/$ID/$VER/public/plugins/$ID/schema/v0alpha1.json"

Worked examples live under settingsExamples.examples, an object keyed by scenario (e.g. apiKey, oauth2ClientCredentials). Each entry has a summary/description (the scenario) and a value holding the jsonData/secureJsonData payload to lift straight into the file:

bash
# list scenarios, then pull one payload
... | jq -r '.settingsExamples.examples | keys[]'
... | jq '.settingsExamples.examples.apiKey.value'

5. Fallback when no schema is published

If schema/dsconfig.json 404s (older plugins):

  • Last resort: the generic structure in grafana-oss skill (§ Data source provisioning) can also tell the user the field names are best-effort, not plugin-authoritative.
NOTE: grafana-oss skill is available in grafana-core plugin and also available as a standalone skill from the https://github.com/grafana/skills repository

6. Map each field by its target

targetYAMLTerraform (grafana_data_source)
roottop-level key on the datasource (url, basicAuth, basicAuthUser)top-level argument (url) / inside json_data_encoded
jsonDataunder jsonData:key inside json_data_encoded = jsonencode({ … })
secureJsonDataunder secureJsonData: as ${ENV_VAR}key inside secure_json_data_encoded = jsonencode({ … }) via a sensitive variable

Use each field's valueType for the scalar (string quoted in YAML, booleantrue/false, number bare). Never inline a real secret. Nested objects (oauth2, aws) and arrays (allowedHosts, scopes) map directly.

Always set access (root target) and default it to proxy — queries route through the Grafana server (the secure default); only use direct (browser → data source) if the user explicitly asks for it. In Terraform the argument is access_mode.

7. Ask the format, then emit the file

Now ask: YAML or Terraform? Same fields, different output file and syntax. Don't assume: "provision X" may mean either; skip the question only if the user already named a format ("terraform for X"). YAML file provisioning is the native, zero-dependency path; Terraform needs the official `grafana/grafana` provider.

ChoiceProduces
YAML config fileprovisioning/datasources/<name>.yaml
Terraform<name>.tf (grafana_data_source resource)

<name> is just the file's basename — cosmetic, since both loaders read every file in the directory regardless of name. Default it to the plugin name.

YAMLprovisioning/datasources/<name>.yaml:

yaml
apiVersion: 1
datasources:
  - name: Infinity # must be unique across the instance — collides even with a different datasource type
    type: yesoreyeram-infinity-datasource # = pluginType from the schema
    access: proxy # always set; default proxy (route queries through the Grafana server)
    uid: infinity-ds # also unique and immutable so dashboards can reference it
    jsonData:
      auth_method: apiKey # value from validations.allowedValues
      apiKeyKey: X-API-Key
      apiKeyType: header
      allowedHosts:
        - https://api.example.com
    secureJsonData:
      apiKeyValue: ${API_KEY} # env var ref, never a literal secret
    editable: false

Terraform<name>.tf:

hcl
variable "api_key" {
  type      = string
  sensitive = true
}

resource "grafana_data_source" "infinity" {
  type        = "yesoreyeram-infinity-datasource"
  name        = "Infinity"
  uid         = "infinity-ds"
  access_mode = "proxy" # always set; default proxy (route queries through the Grafana server)

  json_data_encoded = jsonencode({
    auth_method  = "apiKey"
    apiKeyKey    = "X-API-Key"
    apiKeyType   = "header"
    allowedHosts = ["https://api.example.com"]
  })

  secure_json_data_encoded = jsonencode({
    apiKeyValue = var.api_key
  })
}

grafana_data_source is from the `grafana/grafana` provider — the authoritative reference for argument names (access_mode, json_data_encoded, secure_json_data_encoded). This file is only the resource; the user supplies the required_providers + provider "grafana" block and credentials.

8. Return the file to the user

Present the complete file in a single code block for the user to copy and paste into their environment — note where it goes:

  • YAMLprovisioning/datasources/<name>.yaml (apply on Grafana start or a provisioning reload).
  • Terraform → their Terraform config, applied with terraform apply.

Optionally, tell them how to confirm it worked once applied:

bash
curl -s https://grafana.example.com/api/datasources/uid/<uid>/health \
  -H "Authorization: Bearer <token>"
# { "status": "OK" }    → working
# { "status": "ERROR" } → URL unreachable or auth misconfigured

Or verify in the UI: visit <https://grafana.example.com>/connections/datasources/edit/<uid> and click Test.

Convert an existing data source

To codify a data source already configured in a running instance, read its config through the Grafana MCP server (grafana/mcp-grafana).

Precondition: the Grafana MCP server is connected with its Datasources toolset enabled (it holds the instance credentials). If it isn't available, do not support this path — never ask the user to paste a Grafana token into chat. Fall back to the from-scratch Workflow instead.

  1. Find the data source with the MCP tools — list_datasources to browse, then get_datasource (by uid or name) for the full config.
  2. The result carries every non-secret field directly: type, uid, url, access, basicAuth, basicAuthUser, and the full jsonData object. Copy them as-is.
  3. Secrets are never returned. The secureJsonFields map lists which secret keys are set (e.g. {"apiKeyValue": true}) without their values. Emit an ${ENV_VAR} placeholder in secureJsonData for each key it reports true.
  4. Cross-check against the schema (step 4) to confirm secret key names and target placement, then continue at step 6 (map) and step 7 (emit) as normal.

Related

  • grafana-oss — generic data source / dashboard provisioning structure and provisioning paths.
from this repository

More skills

All skills
grafana
Community

alerting-irm

Configure Grafana Alerting, Incident Response Management (IRM), and SLOs end-to-end — provisions Grafana-managed and data-source-managed alert rules, contact points (Slack/PagerDuty/email/webhook), notification policies with hierarchical matchers, silences, mute timings, on-call schedules and escalation chains, incident-management integrations, and SLOs with multi-window burn-rate alerts. Use when configuring alerts, debugging notification routing, setting up on-call rotations, declaring or managing incidents, defining SLOs, provisioning alerting via YAML or API, picking matchers for a notification policy, building a PagerDuty/Slack webhook receiver, or troubleshooting why an alert isn't firing — even when the user says "page me on errors", "alert me when X happens", "route this to the platform team", or "set up an SLO" without naming Alerting or IRM.

installs
5
GitHub stars
246
Updated
Sep 8
grafana
Community

alloy

Build a unified telemetry pipeline with Grafana Alloy — one OpenTelemetry-compatible binary that collects metrics, logs, traces, and profiles and ships to Grafana Cloud / Prometheus / Loki / Tempo / Pyroscope. Covers the Alloy config language (blocks, sys.env, component refs), prometheus.scrape → remotewrite, loki.source.file + loki.process → loki.write, otelcol.receiver.otlp → otelcol.exporter.otlp, pyroscope.scrape, K8s / Docker / EC2 discovery, relabeling, modules (import.file/git/http), clustering, Fleet Management remotecfg, the Alloy UI at :12345, and alloy fmt / alloy validate. Use when writing a config.alloy, replacing Grafana Agent / OTel Collector, scraping K8s pods, parsing logs, ingesting OTLP, or debugging "Alloy isn't sending anything" — even when the user says "set up the agent", "write me a scrape config", "drop these logs before sending", or "OTel collector config" without naming Alloy.

installs
5
GitHub stars
246
Updated
Sep 8
grafana
Community

beyla

Auto-instrument an application's HTTP / gRPC / DB traffic with Grafana Beyla eBPF — no code changes, no SDK, no restart. Covers requirements (Linux 5.8+ with BTF, CAPSYSADMIN, host PID), language matrix (Go / Java / Python / Ruby / Node / .NET / Rust / C++ / PHP), Docker + Helm + DaemonSet install, port- / process- / Kubernetes-metadata discovery, OTLP traces + Prometheus metrics export, routes decorator (cardinality control), trace sampling, and Grafana Cloud via Alloy. Use when adding observability to a service you can't recompile, instrumenting a closed-source binary, getting RED metrics + spans onto Tempo/Mimir without touching the app, or rolling Beyla as a cluster-wide DaemonSet — even when the user says "zero-code APM", "instrument legacy app", "trace this binary", "eBPF observability", or "no SDK" without naming Beyla.

installs
5
GitHub stars
246
Updated
Sep 8
grafana
Community

dashboarding

Build, modify, and ship Grafana dashboards as JSON via the HTTP API — panel types (timeseries / stat / gauge / table / heatmap / logs / traces / node-graph), gridPos 24-column layout, units, thresholds, template + datasource + chained variables, transformations (organize / calculateField / filterByValue), panel + dashboard links with ${field.labels.x} / ${from}, and Loki/Prometheus annotations. Use when scripting dashboard creation, writing the dashboard JSON for a new service, adding a $job dropdown variable, computing an "Error %" column with a transformation, overlaying deploys as annotations, or pushing a dashboard via POST /api/dashboards/db — even when the user says "create a dashboard for this metric", "add a service dropdown", "show errors as percentage", "overlay our deploys", or "export the dashboard JSON" without naming the API or schema. After every API push, verify with the returned version plus a GET on the dashboard UID.

installs
5
GitHub stars
246
Updated
Sep 8