A dashboard edited by hand in the UI drifts silently. Defining it as a JSON file in a repo turns every change into a reviewable diff.

Dashboards built entirely in the UI have no history. Nobody can say why a panel query changed six months ago, and restoring a deleted dashboard means rebuilding it from memory. Treating the definition as a file checked into a repository fixes both problems at once.

1. Export an existing dashboard as JSON

Every Helix dashboard has an underlying JSON definition, panels, queries, layout, and variables, reachable from the export action or the CLI. Pull it down as the starting point rather than writing one from scratch.

helix dashboard export --id svc-overview-checkout \
  --output dashboards/checkout-api.json

2. Parameterize the parts that repeat

Most teams end up with near-identical dashboards per service, differing only in the service name and a couple of custom panels. A small templating layer turns one JSON file into a generator for all of them.

# dashboards/generate.py
import json

def render(service, extra_metric):
    with open('dashboards/_template.json') as f:
        tpl = json.load(f)
    tpl['variables']['service']['default'] = service
    tpl['panels'].append(extra_metric)
    return tpl

3. Apply through CI, not through the UI

Once a dashboard lives as a file, the deploy step is a CLI call. Wiring it into the same pipeline that ships application code means a dashboard change goes through the same review a config change would.

helix dashboard apply --file dashboards/checkout-api.json

4. Detect drift between the repo and production

Someone will still edit a dashboard directly in the UI during an incident, and that is fine in the moment. What matters is catching it afterward, a scheduled CI job that diffs the live definition against the repo version turns silent drift into a visible pull request.

The point of dashboards as code is not purity, it is that a broken panel has a git blame instead of a shrug.

The first drift check almost always surprises whoever runs it. It is common to find two or three dashboards that were edited live during an old incident and never reconciled back into the repo, quietly diverging further with every UI edit since. Reconciling those once, rather than starting the drift job from a clean slate, is worth doing before turning the check on for good.

  • Export existing dashboards as JSON before writing any new ones by hand.
  • Template the parts that repeat across services instead of copy-pasting whole definitions.
  • Apply changes through CI so dashboard edits go through the same review as code.
  • Run a scheduled drift check between the repo and what is actually live.