<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Foundation SDK on Grafana Labs</title><link>https://grafana.com/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/</link><description>Recent content in Foundation SDK on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/index.xml" rel="self" type="application/rss+xml"/><item><title>Foundation SDK key concepts</title><link>https://grafana.com/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/foundation-sdk-key-concepts/</link><pubDate>Tue, 14 Apr 2026 09:48:24 +0000</pubDate><guid>https://grafana.com/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/foundation-sdk-key-concepts/</guid><content><![CDATA[&lt;h1 id=&#34;foundation-sdk-key-concepts&#34;&gt;Foundation SDK key concepts&lt;/h1&gt;
&lt;p&gt;The Grafana Foundation SDK is built around a few core concepts that make your dashboards structured, reusable, and strongly typed.&lt;/p&gt;
&lt;h2 id=&#34;builders&#34;&gt;Builders&lt;/h2&gt;
&lt;p&gt;The SDK follows a builder pattern, which lets you compose dashboards step-by-step using chained method calls.
Almost every piece of the dashboard, including dashboards, panels, rows, queries, and variables, has its own &lt;code&gt;Builder&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Here are a few you&amp;rsquo;ve already seen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DashboardBuilder&lt;/code&gt; - Starts the dashboard definition and sets global configuration settings like title, UID, refresh interval, time range, etc.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PanelBuilder&lt;/code&gt; - Creates individual visualizations like time series panels, stat panels, or log panels.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DataqueryBuilder&lt;/code&gt; - Defines how a panel fetches data, for example, from Prometheus or the &lt;code&gt;testdata&lt;/code&gt; plugin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Builders can be chained, so you can fluently compose dashboards in a readable, structured way:&lt;/p&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;Go&#34;&gt;Go&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;typescript&#34;&gt;typescript&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Go&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-go&#34;&gt;stat.NewPanelBuilder().
  Title(&amp;#34;Version&amp;#34;).
  Datasource(testdataRef).
  ReduceOptions(common.NewReduceDataOptionsBuilder().
    Calcs([]string{&amp;#34;lastNotNull&amp;#34;}).
    Fields(&amp;#34;/.*/&amp;#34;)).
  WithTarget(
    testdata.NewDataqueryBuilder().
      ScenarioId(&amp;#34;csv_content&amp;#34;).
      CsvContent(&amp;#34;version\nv1.2.3&amp;#34;),
  )&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;typescript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-typescript&#34;&gt;new stat.PanelBuilder()
  .title(&amp;#39;Version&amp;#39;)
  .reduceOptions(new common.ReduceDataOptionsBuilder().calcs([&amp;#39;lastNotNull&amp;#39;]).fields(&amp;#39;/.*/&amp;#39;))
  .datasource(testdataRef)
  .withTarget(new testdata.DataqueryBuilder().scenarioId(&amp;#39;csv_content&amp;#39;).csvContent(&amp;#39;version\nv1.2.3&amp;#39;));&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;types&#34;&gt;Types&lt;/h2&gt;
&lt;p&gt;The Grafana Foundation SDK uses strong types under the hood to help catch mistakes before you deploy a broken dashboard.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When setting a unit, you&amp;rsquo;ll get autocomplete suggestions for valid Grafana units like &lt;code&gt;&amp;quot;percent&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;bps&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When defining a time range, you&amp;rsquo;ll be guided to provide the correct structure, like &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;When referencing data sources, you&amp;rsquo;ll use a structured &lt;code&gt;DataSourceRef&lt;/code&gt; object with defined &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;uid&lt;/code&gt; fields.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This helps you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Avoid typos or unsupported configuration values&lt;/li&gt;
&lt;li&gt;Get full autocomplete and inline documentation in your IDE&lt;/li&gt;
&lt;li&gt;Write dashboards that are less error-prone and easier to maintain&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Strong typing also makes it easier to build reusable patterns and components with confidence, especially in large codebases or teams.&lt;/p&gt;
&lt;h2 id=&#34;options&#34;&gt;Options&lt;/h2&gt;
&lt;p&gt;Most builder methods accept simple values like strings or numbers, but others expect more structured option objects. These are used for things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReduceDataOptions&lt;/code&gt; - How to reduce time series data into single values (e.g. last, avg).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VizLegendOptions&lt;/code&gt; - Configure how the legend of a panel is displayed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CanvasElementOptions&lt;/code&gt; - Define how the the various components of a Canvas panel should be displayed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example using options:&lt;/p&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;Go&#34;&gt;Go&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;typescript&#34;&gt;typescript&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Go&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-go&#34;&gt;stat.NewPanelBuilder().
  ReduceOptions(common.NewReduceDataOptionsBuilder().
    Calcs([]string{&amp;#34;lastNotNull&amp;#34;}).
    Fields(&amp;#34;/.*/&amp;#34;))
  )&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;typescript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-typescript&#34;&gt;new stat.PanelBuilder().reduceOptions(new common.ReduceDataOptionsBuilder().calcs([&amp;#39;lastNotNull&amp;#39;]).fields(&amp;#39;/.*/&amp;#39;));&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By using option builders, you don&amp;rsquo;t need to manually construct deeply nested configuration objects. Instead, the SDK gives you a typed and guided API that mirrors a dashboards internal structure, making it easier to configure complex options without guesswork or referring back to the JSON schema.&lt;/p&gt;
]]></content><description>&lt;h1 id="foundation-sdk-key-concepts">Foundation SDK key concepts&lt;/h1>
&lt;p>The Grafana Foundation SDK is built around a few core concepts that make your dashboards structured, reusable, and strongly typed.&lt;/p>
&lt;h2 id="builders">Builders&lt;/h2>
&lt;p>The SDK follows a builder pattern, which lets you compose dashboards step-by-step using chained method calls.
Almost every piece of the dashboard, including dashboards, panels, rows, queries, and variables, has its own &lt;code>Builder&lt;/code> class.&lt;/p></description></item><item><title>Automate dashboard provisioning with CI/CD</title><link>https://grafana.com/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/dashboard-automation/</link><pubDate>Tue, 14 Apr 2026 09:48:24 +0000</pubDate><guid>https://grafana.com/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/dashboard-automation/</guid><content><![CDATA[&lt;h1 id=&#34;automate-dashboard-provisioning-with-cicd&#34;&gt;Automate dashboard provisioning with CI/CD&lt;/h1&gt;
&lt;p&gt;Managing Grafana dashboards manually can be inefficient and error-prone. With the Grafana Foundation SDK you can define dashboards using strongly typed code, commit them to version control systems, and automatically deploy them using GitHub Actions.&lt;/p&gt;
&lt;h2 id=&#34;why-automate&#34;&gt;Why automate?&lt;/h2&gt;
&lt;p&gt;Automating Grafana dashboard deployment eliminates the need for manual dashboard creation and updates, ensuring that dashboards remain consistent across environments.&lt;/p&gt;
&lt;p&gt;By defending dashboards as code and managing them through CI/CD such as GitHub Actions, you will gain full version control, making it easy to track changes over time and roll back if needed. This also prevents duplication, as the workflow intelligently checks whether a dashboard exists before deciding to create or update it.&lt;/p&gt;
&lt;p&gt;With this fully automated CI/CD pipeline, you can focus on improving your dashboards rather than manually uploading JSON files to Grafana.&lt;/p&gt;
&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#39;https://www.youtube.com/embed/cFnO8kVOaAI&#39; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;You can find the full example source code in the &lt;a href=&#34;https://github.com/grafana/intro-to-foundation-sdk/tree/main/github-actions-example&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Introduction to the Foundation SDK&lt;/a&gt; GitHib repository.&lt;/p&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;This guide shows you how to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate a Grafana dashboard as code and format it for Kubernetes-style deployment&lt;/li&gt;
&lt;li&gt;Use GitHub Actions to deploy, verify, and update the dashboard&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By the end, you&amp;rsquo;ll be able to provision your dashboard as code, and every change to your dashboard will be automatically created or updated in your Grafana instance without manual intervention.&lt;/p&gt;
&lt;h2 id=&#34;1-generate-the-dashboard-json&#34;&gt;1. Generate the dashboard JSON&lt;/h2&gt;
&lt;p&gt;Before deploying a dashboard, 
    &lt;a href=&#34;/docs/grafana/v13.0/as-code/observability-as-code/foundation-sdk/#create-a-dashboard/&#34;&gt;define it as code using the Grafana Foundation SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since Grafana exposes a Kubernetes resource compatible API, you need to make some changes to the code to output the dashboard JSON in the appropriate format.&lt;/p&gt;
&lt;p&gt;This script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generates a Grafana dashboard JSON file&lt;/li&gt;
&lt;li&gt;Wraps it in a Kubernetes-style API format (&lt;code&gt;apiVersion&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;metadata&lt;/code&gt;, &lt;code&gt;spec&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Saves it as &lt;code&gt;dashboard.json&lt;/code&gt; for deployment&lt;/li&gt;
&lt;/ul&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;Go&#34;&gt;Go&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;typescript&#34;&gt;typescript&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Go&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-go&#34;&gt;package main

import (
	&amp;#34;encoding/json&amp;#34;
	&amp;#34;log&amp;#34;
	&amp;#34;os&amp;#34;

	&amp;#34;github.com/grafana/grafana-foundation-sdk/go/cog&amp;#34;
	&amp;#34;github.com/grafana/grafana-foundation-sdk/go/common&amp;#34;
	&amp;#34;github.com/grafana/grafana-foundation-sdk/go/dashboard&amp;#34;
)

type DashboardWrapper struct {
	APIVersion string              `json:&amp;#34;apiVersion&amp;#34;`
	Kind       string              `json:&amp;#34;kind&amp;#34;`
	Metadata   Metadata            `json:&amp;#34;metadata&amp;#34;`
	Spec       dashboard.Dashboard `json:&amp;#34;spec&amp;#34;`
}

type Metadata struct {
	Name string `json:&amp;#34;name&amp;#34;`
}

func main() {
	builder := dashboard.NewDashboardBuilder(&amp;#34;My Dashboard&amp;#34;).
		Uid(&amp;#34;my-dashboard&amp;#34;).
		Tags([]string{&amp;#34;generated&amp;#34;, &amp;#34;foundation-sdk&amp;#34;, &amp;#34;go&amp;#34;}).
		Refresh(&amp;#34;5m&amp;#34;).
		Time(&amp;#34;now-1h&amp;#34;, &amp;#34;now&amp;#34;).
		Timezone(common.TimeZoneBrowser).
		WithRow(dashboard.NewRowBuilder(&amp;#34;Overview&amp;#34;))

	dashboard, err := builder.Build()
	if err != nil {
		log.Fatalf(&amp;#34;failed to build dashboard: %v&amp;#34;, err)
	}

	dashboardWrapper := DashboardWrapper{
		APIVersion: &amp;#34;dashboard.grafana.app/v1&amp;#34;,
		Kind:       &amp;#34;Dashboard&amp;#34;,
		Metadata: Metadata{
			Name: *dashboard.Uid,
		},
		Spec: dashboard,
	}

	dashboardJson, err := json.MarshalIndent(dashboardWrapper, &amp;#34;&amp;#34;, &amp;#34;  &amp;#34;)
	if err != nil {
		log.Fatalf(&amp;#34;failed to marshal dashboard: %v&amp;#34;, err)
	}

	err = os.WriteFile(&amp;#34;dashboard.json&amp;#34;, dashboardJson, 0644)
	if err != nil {
		log.Fatalf(&amp;#34;failed to write dashboard to file: %v&amp;#34;, err)
	}

	log.Printf(&amp;#34;Dashboard JSON:\n%s&amp;#34;, dashboardJson)
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;typescript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-typescript&#34;&gt;import { DashboardBuilder, RowBuilder } from &amp;#39;@grafana/grafana-foundation-sdk/dashboard&amp;#39;;
import * as fs from &amp;#39;fs&amp;#39;;

// Generate the dashboard JSON
const dashboard = new DashboardBuilder(&amp;#39;My Dashboard&amp;#39;)
  .uid(&amp;#39;my-dashboard&amp;#39;)
  .tags([&amp;#39;generated&amp;#39;, &amp;#39;foundation-sdk&amp;#39;, &amp;#39;typescript&amp;#39;])
  .refresh(&amp;#39;5m&amp;#39;)
  .time({ from: &amp;#39;now-1h&amp;#39;, to: &amp;#39;now&amp;#39; })
  .timezone(&amp;#39;browser&amp;#39;)
  .withRow(new RowBuilder(&amp;#39;Overview&amp;#39;))
  .build();

// Convert to Kubernetes-style format
const dashboardWrapper = {
  apiVersion: &amp;#34;dashboard.grafana.app/v1&amp;#34;,
  kind: &amp;#34;Dashboard&amp;#34;,
  metadata: {
    name: dashboard.uid!
  },
  spec: dashboard
};

// Save the formatted JSON to a file
const dashboardJSON = JSON.stringify(dashboardWrapper, null, 2);
fs.writeFileSync(&amp;#39;dashboard.json&amp;#39;, dashboardJSON, &amp;#39;utf8&amp;#39;);

console.log(`Dashboard JSON:\n${}`);&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;2-automate-deployment-with-github-actions&#34;&gt;2. Automate deployment with GitHub Actions&lt;/h2&gt;
&lt;p&gt;Next, set up GitHub Actions to automate the deployment of a Grafana dashboard using the Foundation SDK and the 
    &lt;a href=&#34;/docs/grafana/v13.0/as-code/observability-as-code/grafana-cli/&#34;&gt;&lt;code&gt;grafanactl&lt;/code&gt; CLI tool&lt;/a&gt; to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract the dashboard name from &lt;code&gt;dashboard.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Check if the dashboard already exists within our Grafana instance&lt;/li&gt;
&lt;li&gt;Update it if it does, create it if it doesn’t&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The following GitHub Action configuration assumes you are using a Go-based dashboard generator. If you&amp;rsquo;re using one of the other languages that the Foundation SDK supports, modify the &lt;strong&gt;Generate Dashboard JSON&lt;/strong&gt; step accordingly.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;.github/workflows/deploy-dashboard.yml&lt;/code&gt; deploy workflow looks like:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;name: Deploy Grafana Dashboard

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.24.6

      - name: Verify Go version
        run: go version

      - name: Download and Extract grafanactl
        run: |
          curl -L -o grafanactl-x86_64.tar.gz &amp;#34;https://github.com/grafana/grafanactl/releases/download/${{ vars.GRAFANACTL_VERSION }}/grafanactl_Linux_x86_64.tar.gz&amp;#34;
          tar -xzf grafanactl-x86_64.tar.gz
          chmod &amp;#43;x grafanactl
          sudo mv grafanactl /usr/local/bin/grafanactl

      - name: Generate Dashboard JSON
        working-directory: ./github-actions-example
        run: go run main.go

      - name: Deploy Dashboard with grafanactl
        env:
          GRAFANA_SERVER: ${{ vars.GRAFANA_SERVER }}
          GRAFANA_STACK_ID: ${{ vars.GRAFANA_STACK_ID }}
          GRAFANA_TOKEN: ${{ secrets.GRAFANA_TOKEN }}
        run: |
          if [ -f dashboard.json ]; then
            echo &amp;#34;dashboard.json exists, deploying dashboard.&amp;#34;
            grafanactl resources push dashboards --path ./dashboard.json
          else
            echo &amp;#34;dashboard.json does not exist.&amp;#34;
            exit 1
          fi
        working-directory: ./github-actions-example&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;1-checkout-and-set-up-go&#34;&gt;1. Checkout and set up Go&lt;/h3&gt;
&lt;p&gt;To set up Go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check out the repository to access the project code.&lt;/li&gt;
&lt;li&gt;Install Go 1.24.6 using the &lt;code&gt;actions/setup-go&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;Verify Go is properly installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-download-and-install-grafanactl&#34;&gt;2. Download and install &lt;code&gt;grafanactl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Next, download the &lt;code&gt;grafanactl&lt;/code&gt; CLI from GitHub using the version defined in &lt;code&gt;vars.GRAFANACTL_VERSION&lt;/code&gt;. It unpacks the tarball, makes it executable, and moves it to a location in the system &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;3-generate-the-dashboard-json&#34;&gt;3. Generate the dashboard JSON&lt;/h3&gt;
&lt;p&gt;Next, run the dashboard generator (&lt;code&gt;main.go&lt;/code&gt;) from the &lt;code&gt;./github-actions-example&lt;/code&gt; director to produce a &lt;code&gt;dashboard.json&lt;/code&gt; file that contains the Grafana dashboard definition.&lt;/p&gt;
&lt;h3 id=&#34;4-deploy-the-dashboard-with-grafanactl&#34;&gt;4. Deploy the dashboard with &lt;code&gt;grafanactl&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If &lt;code&gt;dashboard.json&lt;/code&gt; already exists, it is deployed to your Grafana instance using:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;grafanactl resources push dashboards --path ./dashboard.json&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This command authenticates against Grafana using the following environment variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GRAFANA_SERVER&lt;/code&gt;: Your Grafana instance URL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GRAFANA_STACK_ID&lt;/code&gt;: Your Grafana stack ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GRAFANA_TOKEN&lt;/code&gt;: A Grafana service account token with sufficient permissions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;github-variables-and-secrets-used&#34;&gt;GitHub variables and secrets used&lt;/h3&gt;
&lt;p&gt;Verify these variables are configured in your repository under &lt;strong&gt;Settings &amp;gt; Security &amp;gt; Secrets and variables &amp;gt; Actions&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vars.GRAFANACTL_VERSION&lt;/code&gt;: Version of &lt;code&gt;grafanactl&lt;/code&gt; to install&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vars.GRAFANA_SERVER&lt;/code&gt;: The URL of your Grafana instance&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vars.GRAFANA_STACK_ID&lt;/code&gt;: The stack ID in Grafana&lt;/li&gt;
&lt;li&gt;&lt;code&gt;secrets.GRAFANA_TOKEN&lt;/code&gt;: Grafana API token&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This action ensures that every push to &lt;code&gt;main&lt;/code&gt; will regenerate and deploy your latest dashboard definition to Grafana.&lt;/p&gt;
]]></content><description>&lt;h1 id="automate-dashboard-provisioning-with-cicd">Automate dashboard provisioning with CI/CD&lt;/h1>
&lt;p>Managing Grafana dashboards manually can be inefficient and error-prone. With the Grafana Foundation SDK you can define dashboards using strongly typed code, commit them to version control systems, and automatically deploy them using GitHub Actions.&lt;/p></description></item></channel></rss>