skip to content

Provisioning and Dashboards-as-Code

Managing Grafana declaratively: the dashboard JSON model and provisioning files that make dashboards reproducible. Interviewers ask because click-built dashboards don't survive environments or reviews.

on this pageshow

questions

5

Grafana can load dashboards from YAML provider files in its provisioning directory. Explain what that provider actually does at runtime, and what changes for an engineer who then opens one of those dashboards in the UI and tries to save an edit.

level: middleimportance: must knowfreq 40%

answer

  1. Files → DB, one way; DB still serves
  2. provisioning/dashboards/*.yaml, GF_PATHS_PROVISIONING
  3. updateIntervalSeconds rescan — no restart needed
  4. Provisioned = read-only UI; allowUiUpdates is an escape hatch
  5. File deleted → dashboard deleted unless disableDeletion

basics

~20 s

A file provider tells Grafana to scan a directory of dashboard JSON files and load them into its database, rescanning periodically so file changes apply without a restart. Provisioned dashboards are read-only in the UI by default: saving is refused unless the provider sets allowUiUpdates, and removing the file removes the dashboard.

solid answer

~60 s

Provisioning is a **one-way push from files into Grafana's database**. A dashboard provider entry (in `provisioning/dashboards/*.yaml`, under the path given by `GF_PATHS_PROVISIONING`) declares `type: file`, an `options.path` directory, a target `folder` or `folderUid` — or `foldersFromFilesStructure` to mirror the directory tree as folders — and an `updateIntervalSeconds` controlling how often Grafana rescans. Grafana reads every JSON file under the path, inserts or updates the dashboards, and keeps serving them from the database as normal; the files are the source, not the serving store. The UI consequence is the part interviewers push on. A provisioned dashboard is marked as such and is **read-only**: the save action is refused, with the UI offering to copy the JSON so you can commit it instead. Setting `allowUiUpdates: true` permits UI saves, but the next scan that sees a changed file overwrites them — an escape hatch, not a workflow. **Deleting the file deletes the dashboard** on the next scan unless `disableDeletion: true`. Data source and alerting providers use the same directory but are applied at startup (or via the provisioning reload API), not on the dashboard rescan interval.

code

text · 12 lines
text
apiVersion: 1
providers:
  - name: platform-dashboards
    orgId: 1
    folder: Platform
    type: file
    disableDeletion: false
    allowUiUpdates: false        # provisioned dashboards stay read-only
    updateIntervalSeconds: 30    # rescan; no Grafana restart needed
    options:
      path: /var/lib/grafana/dashboards
      foldersFromFilesStructure: true

go deeper

for a junior

Know that a YAML provider points Grafana at a directory of dashboard JSON files and that those dashboards cannot be saved from the UI.

for a middle

Explain the one-way file-to-database load, the rescan interval, and the meaning of allowUiUpdates, disableDeletion and foldersFromFilesStructure.

for a senior

Cover the operational edges: uid stability across refactors, silent skips on invalid JSON, deletion semantics, and the different reload path for data sources.

for a principal

Frame the read-only UI as the mechanism that keeps a single source of truth, and set policy for which folders are code-owned versus UI-owned.

## The mental model Grafana always serves dashboards from its own database. Provisioning does not change that; it adds a **loader** that reads files on disk and writes them into that database. The relationship is one-way: files → database. Nothing you do in the UI writes back to the files, which is exactly why the UI has to restrict editing — otherwise the two would drift and the next scan would throw your work away without warning. ## The provider file Provider files live under the provisioning directory, whose location is set by `GF_PATHS_PROVISIONING` (in containers usually `/etc/grafana/provisioning`). Subdirectories separate the kinds: `dashboards/`, `datasources/`, `alerting/`, `plugins/`, and access-control in editions that support it. A dashboard provider entry typically carries: - `name` — a label for the provider; also the provisioning identity attached to each dashboard it loads. - `type: file` — read from disk. - `orgId` — which organisation the dashboards belong to. - `folder` / `folderUid` — the destination folder; created if missing. - `options.path` — the directory to scan, recursively. - `options.foldersFromFilesStructure: true` — build the folder hierarchy from the directory layout instead of putting everything in one folder. - `updateIntervalSeconds` — how often Grafana rescans (small default, on the order of ten seconds). - `disableDeletion` — keep dashboards whose files disappeared. - `allowUiUpdates` — permit saving edits in the UI. ## Runtime behaviour On start, and then on every interval, Grafana walks the path, reads each JSON file, and upserts the dashboard. Identity comes from the dashboard's **`uid`** (plus the provider and folder); a file whose JSON has no stable uid can be recreated as a new dashboard when things move, losing links and history. This is why "always set a uid in the JSON" is the first rule of dashboards-as-code. Because the scan is periodic, a config-map update or a volume sync propagates **without restarting Grafana** — a genuinely useful property in Kubernetes, where dashboards are commonly mounted from ConfigMaps. Data sources are different: their provider files are read at startup, and otherwise only when the admin provisioning **reload API** is called; a rotated credential in a datasource file does not take effect by itself on the dashboard interval. ## The UI restriction Provisioned dashboards are flagged in the database. The UI shows the provisioned state, and saving is blocked: instead you get the JSON to copy into your repository. That is not an inconvenience to be worked around — it is the mechanism that keeps the file the single source of truth. Two knobs modify it: - `allowUiUpdates: true` lets the UI save into the database. The file remains authoritative in the sense that when Grafana next detects a *changed* file, it overwrites the database copy. The result is a system where edits survive right up until the moment someone touches the file, which is the worst possible failure mode for a shared dashboard. Use it for migration, not steady state. - `disableDeletion: true` stops a vanished file from removing the dashboard. Useful while reorganising a repository; it also means orphaned dashboards accumulate silently, so it is not a free safety net. ## Common gotchas - **Deleting a file deletes the dashboard.** A refactor that renames directories can wipe and recreate dashboards, breaking links unless uids are stable. - **Invalid JSON is skipped**, and the only signal is a line in the Grafana log. Nothing surfaces in the UI. Validate in CI. - **The dashboard's numeric `id` must not be carried over** from another instance; identity belongs to `uid`. - **The folder must be reachable by the users who need it.** Provisioning places dashboards in folders but does not, in the open-source file-provisioning path, express fine-grained permissions on them. - **Files are not a queue**: the same uid provisioned from two providers or two files fights over the same dashboard, last scan wins. ## How to answer The crisp version: *provisioning is a one-way loader from files into Grafana's database, rescanned on an interval; the UI goes read-only so the files stay authoritative, deletion of a file deletes the dashboard, and `allowUiUpdates` is a migration escape hatch rather than a workflow.*

  • Someone asks for allowUiUpdates to be turned on so their team can tweak panels quickly. What do you tell them?
    It works, but it creates a system where UI edits persist only until the next time the file changes, after which they vanish with no notification — the most confusing possible outcome for a shared dashboard. The honest options are to keep it off and edit through the repository, or to let that team own an unprovisioned dashboard in their own folder where the UI is authoritative. Use allowUiUpdates for a bounded migration, not as a steady state.
  • You update a dashboard JSON file in a mounted ConfigMap. Does Grafana pick it up, and what about a changed data source credential in the same provisioning directory?
    The dashboard is picked up on the next rescan, governed by updateIntervalSeconds, with no restart — although the ConfigMap-to-file propagation delay inside the container is added on top. Data sources are not on that loop: their provider files are read at startup and otherwise only when the admin provisioning reload API is called, so a rotated credential requires a reload or a restart to take effect.

saying these in an interview costs you the question

  • Believing provisioned dashboards are served from the files, rather than loaded into the database
  • Assuming a UI save is possible and reporting a bug when it is refused
  • Enabling allowUiUpdates as the normal workflow and being surprised when edits vanish
  • Not setting a stable uid in the JSON, so moving or renaming files recreates dashboards and breaks links
  • Expecting a data source credential change to be picked up on the dashboard rescan interval

context

open as a page

You export a Grafana dashboard's JSON and commit it so the same file can be deployed to dev, staging and production. Which parts of the JSON model determine whether it works unchanged in all three, and what must be removed or parameterised first?

level: middleimportance: must knowfreq 34%

basics

~20 s

Keep a stable uid, drop the numeric id, and stop hardcoding per-instance data source UIDs in panels — either pin the same data source UID in every environment or drive panels from a data-source template variable. Also expect schemaVersion migration and version churn to add diff noise.

open as a page

Grafana's unified alerting can be delivered from files in the provisioning directory alongside dashboards and data sources. What rules does that delivery mechanism impose — object identity, what is replaced versus merged, and what happens to those objects in the UI?

level: seniorimportance: should knowfreq 24%

basics

~20 s

Alerting provisioning files declare rule groups, contact points, notification policies, mute timings and templates. Every rule needs a stable uid or reloads recreate it and lose its state. Provisioned objects are read-only in the UI. The notification policy tree is a single root object, so provisioning it replaces the whole tree rather than merging.

open as a page

You need to provision a Grafana data source that requires a password or API token, without committing the secret to the repository that holds the provisioning files. What mechanisms does Grafana give you, and what happens to that secret afterwards?

level: seniorimportance: should knowfreq 32%

basics

~20 s

Put the secret under secureJsonData in the datasource provisioning file, but reference it indirectly: Grafana interpolates environment variables and can read a value from a mounted file. Grafana encrypts secureJsonData in its database and never returns it through the API, so rotation means changing the source and reloading provisioning.

open as a page

For a platform running several Grafana instances across environments and teams, compare delivering dashboards, data sources and folder access as files on disk, via the Terraform Grafana provider, and via a Kubernetes operator with custom resources. What decides the choice, and where does each one hurt?

level: principalimportance: should knowfreq 28%

basics

~20 s

Files are simplest but need filesystem access, express no permissions and have no drift detection. Terraform drives the HTTP API, so it reaches hosted instances and can manage folders, teams and permissions, at the cost of state ownership and destroy blast radius. An operator reconciles custom resources continuously and fits GitOps and many instances, at the cost of a controller and CRD versioning.

open as a page