grafana-dash-gen: building Grafana dashboards as code
grafana dash dash dash gen
At a glance
- What is it?
- Grafana Dash Gen is a TypeScript library from Uber that models a Grafana dashboard as objects, with rows, panels, graphite targets, templates, annotations and alerts, so a dashboard can be generated as JSON or published to a Grafana instance. It suits a team that wants dashboards in version control, and it is built around the older Grafana JSON model rather than the current schema.
- Who is it for?
- grafana-dash-gen fits a team that wants Grafana dashboards defined in code and stored in a repository, since the object model covers rows, panels, targets, templates, annotations and alerts, and since the dashboard can be published or printed as JSON for a pipeline to pick up.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 96 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The vocabulary the library is built on
Grafana Dash Gen is described as a collection of utility classes to construct and publish Grafana graphs, and the readme is explicit that the library was built ground up to incorporate Grafana terminologies.
The vocabulary is the API. A Dashboard represents the final dashboard that is displayed. A Row is a row in Grafana, and a dashboard consists of many rows. A Panel is a visual display item, which could be a graph, a single stat or others, and a row consists of many panels. A Target is a dot separated graphite string, for example a.b.count, and a panel consists of many targets. Annotations are lined markers that annotate a graph, and a dashboard can have annotations added to it. Templates are variables that can be included in the state, for example a.$dc.b.count to switch between datacenters, and a dashboard can have templates added to it.
That last one is worth pausing on, because it describes the era this library comes from. The target is a graphite-style dotted path, the templates are Grafana's older $variable substitution, and the panels are the older Graph and SingleStat types. Grafana has moved on considerably since then, and the current dashboard JSON, the data source model and the panel plugin system all look different. The library is a faithful model of the Grafana that existed when it was written.
The functional consequence is that if your Grafana instance is recent and uses the modern schema, generated dashboards will need work to display. If your stack is still on the older JSON shape, or if you are generating dashboards for a Grafana that renders them as-is, the vocabulary lines up.
The library is MIT licensed, the primary language is TypeScript, the package name is grafana-dash-gen and the version in the manifest is 4.1.1. The last push to the repository was on 2026-07-19, and the repository publishes no GitHub releases, so the changelog in the repository is the release history.
Configuring and creating a dashboard
The usage guide is a six-step sequence, and the first step is optional.
Step 1 is to configure Grafana, and the readme says this is only needed if you want Grafana to publish the dashboard for you:
const grafana = require('grafana-dash-gen');
const Row = grafana.Row;
const Dashboard = grafana.Dashboard;
const Panels = grafana.Panels;
const Target = grafana.Target;
const Templates = grafana.Templates;
const Alert = grafana.Alert;
const Condition = grafana.Condition;
grafana.configure({
url: 'https://your.grafana.com/elasticsearch/grafana-dash/dashboard/',
cookie: 'auth-openid=someidhere'
});Two things about that configuration are notable. The URL is an Elasticsearch-era Grafana API path, the older endpoint that Grafana kept for compatibility, and the cookie is a single auth-openid value. That tells you the publishing mechanism was designed for Grafana instances behind OpenID Connect with a session cookie, and it also tells you how old the endpoint assumptions are.
Step 2 creates the dashboard, and the minimal form is:
const dashboard = new Dashboard({
title: 'Api dashboard'
});The fuller form adds a slug, a templating list and annotations:
const dashboard = new Dashboard({
title: 'Api dashboard',
slug: 'api',
templating: [{
name: 'dc',
options: ['dc1', 'dc2']
}, {
name: 'smoothing',
options: ['30min', '10min', '5min', '2min', '1min']
}],
annotations: [{
name: 'Deploy',
target: 'stats.$dc.production.deploy'
}]
});The templating entry defines a variable with its allowed options, which becomes the $dc in target strings, and the annotations entry attaches a named marker to a graphite path, which is how a deploy gets marked on a graph. The readme notes that if you do not want templates or annotations you can leave them out.
Rows, panels and the graphite target builder
Step 3 creates a row, which is a one-liner, and step 4 adds panels to it.
The panel can carry its row and dashboard at construction time:
const panel = new Panels.Graph({
title: 'api req/sec',
span: 5,
targets: [
new Target('api.statusCode.*').
transformNull(0).sum().hitcount('1seconds').scale(0.1).alias('rps')
],
row: row,
dashboard: dashboard
});or you can create it separately and attach it afterwards with row.addPanel(panel). The span is the row-width the panel occupies, and the readme notes that a full width single stat can be created by making a new Row on the fly:
const requestVolume = new Panels.SingleStat({
title: 'Current Request Volume',
postfix: 'req/sec',
targets: [
new Target('stats.$dc.counts').
sum().scale(0.1)
],
row: new Row(),
dashboard: dashboard
});The target builder is the most distinctive part of the library. A Target starts with a dotted path and then you chain the graphite functions: transformNull(0) replaces null values, sum() aggregates, hitcount('1seconds') buckets the hit count, scale(0.1) applies a multiplier, and alias('rps') names the series. Every method returns the target, so the whole expression reads as a single graphite query written in JavaScript.
That is the feature that makes the library worth using for its original purpose. If your metrics are in graphite, you can express a complex query with a fluent builder instead of concatenating strings, and the type checker will catch a method name that does not exist.
The cost is the same coupling in reverse. If your metrics come from Prometheus, InfluxDB or a SQL data source, this builder is the wrong shape, because a graphite path with chained functions has no direct equivalent in those query languages.
Alerts and publishing
Step 5 covers alerts, and the readme notes they are optional. An alert is set on a target, and each target added to the panel receives a refId of A, B, then up to Z.
A condition is built with a chain of onQuery, withEvaluator and withReducer:
const conditionOnRequestLowVolume = new Condition()
.onQuery('A')
.withEvaluator(1, 'lt')
.withReducer('max');
const alert = new Alert({ name: 'Low volume of requests' });
alert.addCondition(conditionOnRequestLowVolume);The onQuery call takes the refId, so the condition refers to the first target in the panel, the evaluator takes a threshold value and an operator, here 1 and lt, and the reducer says how to aggregate the series before comparing.
There is a shorter form where the alert is constructed with the condition, and an alert can also be passed into the Graph constructor directly.
Step 6 publishes, with a single call:
grafana.publish(dashboard);and if you want the JSON rather than a publish, the dashboard can generate it directly:
console.log(JSON.stringify(dashboard.generate()));That generate call is what makes the library usable in a pipeline. You do not have to publish to Grafana at all; you can produce the dashboard JSON and hand it to whatever deploys it, which is the arrangement a team that keeps dashboards in version control wants.
The readme also points at example.js as a complete example of a dashboard, and that file is listed among the published files in the package manifest along with the src/ directory and the compiled grafana/ output.
Where grafana-dash-gen is the wrong choice
The first limitation is the Grafana version it targets. The publishing URL is the old Elasticsearch-era endpoint, the templates use the older $variable convention, the panels are Graph and SingleStat rather than the current panel plugins, and the targets are graphite paths. Grafana has changed its dashboard JSON schema several times since, and a dashboard generated here will not render as intended on a current instance without editing the JSON. A team on a modern Grafana should be using the official dashboard-as-code tooling rather than this.
The second is the data source assumption. The target builder is graphite. If your metrics live in Prometheus, InfluxDB or a database, you would be writing the query outside the library and the fluent target API gives you nothing, and the type-safe part of the value disappears.
The third is the publishing mechanism, which is a session cookie against a legacy endpoint. There is no service account token flow, no Grafana Cloud API key handling, no permissions model, and no retry. In a CI job that means embedding a credential in an environment variable and trusting an old endpoint still behaves.
The fourth is that the project is quiet. The last push was on 2026-07-19, there are no GitHub releases, and the manifest version is 4.1.1 while the CHANGELOG.md in the repository is the only record of what changed. The dependencies are old in places too, node-fetch at 2.x and a string-helper library at 1.13, both of which have had significant releases since. The dependency list also includes an error package at 10.4.0, which is a library that was renamed, and having it as a direct dependency rather than following the rename is a sign of the dependency list not being revisited.
The fifth is that the toolkit is a dashboard builder and nothing else. There is no datasource provisioning, no folder management, no alert rule management beyond the dashboard JSON, no organisation or permission handling, and no plugin management. If you need a full Grafana-as-code pipeline, this library covers one step of it.
Editorial conclusion
grafana-dash-gen fits a team that wants Grafana dashboards defined in code and stored in a repository, since the object model covers rows, panels, targets, templates, annotations and alerts, and since the dashboard can be published or printed as JSON for a pipeline to pick up. It is the wrong choice if your Grafana instance runs a modern schema, because the library models the older dashboard JSON with graphite-style targets, and it is the wrong choice if you want an official Terraform or Grafana provider instead. Before adopting it, check that your dashboard JSON shape matches what the library generates, and note that the last push was on 2026-07-19 with the package at version 4.1.1 under an MIT licence and no GitHub releases published.
Frequently asked questions
What is Grafana Dash Gen?
It is a collection of utility classes to construct and publish Grafana graphs, built ground up around Grafana terminology with Dashboard, Row, Panel, Target, Annotations and Templates. It is MIT licensed, published as grafana-dash-gen, and the package version is 4.1.1.
How do I install and test grafana-dash-gen?
Install it with pnpm install grafana-dash-gen or npm install grafana-dash-gen, and run the test suite with pnpm test, which runs the fast jest pass and then the coverage pass. The package also exposes a build script that compiles with tsc and a typecheck script.
How do I build a graphite target with grafana-dash-gen?
Create a Target with a dotted path and chain the graphite functions, for example new Target('api.statusCode.*').transformNull(0).sum().hitcount('1seconds').scale(0.1).alias('rps'). Each method returns the target so the whole query reads as one expression.
Can grafana-dash-gen publish a dashboard to Grafana?
Yes. You configure it with grafana.configure, giving a url and a cookie, and then call grafana.publish(dashboard). The url in the documented example is the Elasticsearch-era dashboard API path. If you only want the JSON, call JSON.stringify(dashboard.generate()) instead.
How do I add an alert to a panel with grafana-dash-gen?
Alerts are optional and are set on a target. Build a Condition with onQuery, withEvaluator and withReducer, attach it to an Alert with addCondition, and add the alert to the panel. Each target in a panel receives a refId of A, B and so on, which is what onQuery refers to.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/uber-grafana-dash-gen)Was this useful?