Generated banner for App SDK Concepts
Generated logo for App SDK Concepts

App SDK Concepts

Grafana LabsOfficialPublished by Grafana Labs

  • Skill
  • Tool integration
  • Cloud and DevOps
  • Apache-2.0
  • Medium risk

From the author

Use when starting any grafana-app-sdk work — scaffolding a Grafana app, initializing a Grafana App Platform app, picking a deployment mode (standalone operator / grafana/apps / frontend-only), wiring app-specific config, or onboarding to the SDK. Covers `grafana-app-sdk` CLI install, `project init` per deployment mode, project layout, the schema-centric workflow (CUE kinds → generated code → reconciler/admission logic), and `SpecificConfig` for env-driven app configuration. Use even if the user just says "make a new app", "Grafana app platform", "kinds and watchers", "operator scaffold", or asks about `apps/` inside the Grafana repo, without naming the SDK explicitly.
— the description by Grafana Labs

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The grafana-app-sdk provides a CLI and Go library for building schema-centric applications on the Grafana App Platform. It supports a workflow where developers define resources using CUE schemas, generate Go and TypeScript code, and implement business logic through reconcilers and admission controllers. The SDK supports multiple deployment modes, including standalone Kubernetes operators and in-process applications within the Grafana repository.

What it does

  • Initializes new application projects with the required directory structure and build files
  • Scaffolds Kubernetes operator components or frontend plugin structures
  • Generates Go types, clients, and TypeScript definitions from CUE schemas
  • Provides commands for local development and testing of application logic
  • Facilitates the creation of Kubernetes YAML bundles for deployment
  • Supports configuration management for environment-driven application settings

When to use it

  • When starting a new project on the Grafana App Platform
  • When you need to define custom resources using CUE schemas
  • When building a standalone Kubernetes operator for Grafana-related tasks
  • When integrating a new application directly into the Grafana repository
  • When you need to generate boilerplate code for reconcilers and admission handlers

Advantages

  • Ensures consistent project structure across different deployment modes
  • Automates the generation of boilerplate code from schema definitions
  • Simplifies the integration of business logic with Kubernetes-style resources
  • Provides a unified CLI for the entire development lifecycle
  • Supports both standalone and in-process deployment architectures

Usage examples

“How do I start a new Grafana app project?”
Use the command grafana-app-sdk project init github.com/your-org/your-app to create the project structure, including kinds, package skeletons, and build files.
“How do I add an operator to my project?”
Run grafana-app-sdk project component add operator to scaffold the necessary reconciler stubs, admission handlers, and the operator entrypoint.
“How do I update my Go types after changing a CUE schema?”
Execute the command grafana-app-sdk generate to update Go types, clients, and TypeScript definitions based on your latest CUE definitions.
“How do I run my app locally?”
Use the command grafana-app-sdk local/up to start a local Kubernetes-compatible API server for testing your application logic.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/grafana/app-sdk-concepts/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip app-sdk-concepts.zip -d .agents/skills

Documentation by Grafana Labs

Grafana App SDK Concepts

The grafana-app-sdk is a CLI + Go library for building schema-centric apps on the Grafana App Platform. Apps define resources via CUE schemas ("kinds"), generate Go + TypeScript code, and implement business logic via admission control and reconcilers.

Prerequisites

go install github.com/grafana/grafana-app-sdk/cmd/grafana-app-sdk@latest
grafana-app-sdk version   # verify

Common Workflows

Scaffold a standalone operator app
# 1. Init the project (use the Go module path)
grafana-app-sdk project init github.com/example/my-app

# 2. Add operator scaffolding — ASK THE USER FIRST.
#    They may prefer to write app.App by hand.
grafana-app-sdk project component add operator

# 3. Verify scaffolded layout
ls pkg/app pkg/watchers cmd/operator
# Expected: app.go, watchers/<kind>.go, main.go

Common failure: forgetting go install updates the binary — verify with grafana-app-sdk version before init.

Scaffold a grafana/apps-style app (inside grafana/grafana)

Only available inside the Grafana repo (or fork) — the init command detects apps/ and pkg/registry/apps/ at the repo root.

mkdir -p apps/my-app && cd apps/my-app
grafana-app-sdk project init github.com/grafana/grafana/apps/my-app

# Keep ONLY: kinds/ pkg/ go.mod go.sum — delete everything else.
cp apps/example/Makefile       apps/my-app/Makefile
cp apps/example/kinds/config.cue apps/my-app/kinds/config.cue   # overwrite
go work use ./apps/my-app

Then register the app inside Grafana (pkg/registry/apps/apps.go + register.go). Full walkthrough in references/deployment-modes.md.

End-to-end development loop
1. project init               → module, Makefile, kinds/
2. project kind add MyKind    → CUE kind scaffold
3. Edit kinds/*.cue           → schemas, validation, versions
4. grafana-app-sdk generate   → Go types, clients, TS types, AppManifest, CRDs
5. Implement logic            → fill in reconciler / admission stubs
6. (optional) project component add frontend

Always rerun generate after every CUE change — generated code is the API your reconciler sees.

Deployment modes (one-line table)

ModeWhen to pickWhere it runs
Standalone operatorOutside Grafana repo, want your own binaryKubernetes operator with its own webhook server
grafana/appsInside github.com/grafana/grafana (or fork)In-process inside Grafana's API server
Frontend-onlyUI-only app, no Go logic neededNo backend — TS types only

Full per-mode init, runtime, and wiring detail in references/deployment-modes.md.

References

Resources

Files

references/local-development.md

Local Development Guide

Standalone Operator Mode

Standard Way from Generated Files

The grafana-app-sdk generates a standard way of running a kubernetes cluster locally with grafana, datasources, and app setup using k3d and tilt.

Prerequisites
Create Cluster

The generated Makefile has the target make local/up to create the cluster and apply everything. This runs:

  • grafana-app-sdk project local generate - generates a k3d config (./local/generated/k3d-config.json) to mount the host volume ./local/mounted-files and a YAML bundle in ./local/generated/dev-bundle.yaml.

  • ./local/scripts/cluster.sh create "local/generated/k3d-config.json" to create the cluster

  • tilt up in the local directory to stand up all resources.

local/Tiltfile is generated by project init and will scrape all YAML in local/generated, and then all YAML in local/additional (which overwrites anything declared in local/generated).

Push Operator Image

The operator image must be built with make build and then pushed to the local cluster with make local/push_operator

Deploy Plugin

The plugin for the app can be pushed to the local grafana deployment with make local/deploy_plugin. The plugin must have been built already (make build). By default, the grafana deployment loads the plugin from local/mounted-files/plugin/dist.

Configuration

The local setup can be configured with the file local/config.yaml (generated by project init).

See local-config.md for a full reference of all available configuration options.

Testing with kubectl

Once CRDs are applied and the operator is running, create test resources directly:

# Create a resource
kubectl apply -f - <<EOF
apiVersion: my-app.grafana.app/v1alpha1
kind: MyKind
metadata:
  name: test-resource
  namespace: default
spec:
  title: "Test"
  description: "A test resource"
EOF

# Watch the resource status update as the reconciler runs
kubectl get mykind test-resource -w

# See full status
kubectl describe mykind test-resource

# Delete it
kubectl delete mykind test-resource
Debug Logging

By default, the generated operator code uses debug-level logging when it instantiates the global default logger:

// main.go
func main() {
  // Configure the default logger to use slog
	logging.DefaultLogger = logging.NewSLogLogger(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelDebug,
	}))
  // ... rest of code
}

An app author may change this to read from a config file or CLI, in order to find our, either ask the user or read cmd/operator/main.go to see how the logging is configured.

Alternative Local Dev Methods
Prerequisites

A local Kubernetes cluster is required. The easiest options:

# Option A: kind (Kubernetes in Docker)
brew install kind
kind create cluster --name dev

# Option B: minikube
brew install minikube
minikube start

# Confirm kubectl is pointing at the local cluster
kubectl config current-context
kubectl get nodes
Apply CRDs

Before running the operator, apply the generated CRDs to the cluster:

# Apply all generated CRD files
kubectl apply -f definitions/

kubectl apply -f definitions/ will also attempt to apply the <app>-manifest.(json|yaml) file, which is not a valid Kubernetes resource and will produce an error. This error can be safely ignored — the CRD files will still be applied successfully.

Run this again after every grafana-app-sdk generate if schema fields changed.

Run the Operator Locally

Build and run the operator binary against the local cluster:

# Run directly with go run
go run ./cmd/operator/... --kubeconfig="$HOME/.kube/config"

# Or build first then run
make build
./bin/operator --kubeconfig="$HOME/.kube/config"

The operator uses the standard kubeconfig by default — it will connect to whatever cluster kubectl points to.


grafana/apps Mode

For grafana/apps, local development means running the full Grafana binary with your app registered.

Build and Run Grafana

From the Grafana repo root:

# Build the backend (includes your app)
make build-go

# Run Grafana with your app registered
./bin/grafana server

# Or use the dev mode that watches for changes
make run

Your app is automatically included in the binary because it's registered in pkg/registry/apps/apps.go.

Testing with Grafana UI
  1. Navigate to http://localhost:3000

  2. Use the Grafana API or UI to create resources of your kind

  3. Watch server logs for reconciler/admission output

API Access

Your kind is accessible via the Grafana API at:

GET/POST /apis/<group>/<version>/namespaces/<namespace>/<plural>

For example:

# List resources
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:3000/apis/my-app.grafana.app/v1alpha1/namespaces/default/mykinds

# Create a resource
curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"apiVersion":"my-app.grafana.app/v1alpha1","kind":"MyKind","metadata":{"name":"test"},"spec":{"title":"Test"}}' \
  http://localhost:3000/apis/my-app.grafana.app/v1alpha1/namespaces/default/mykinds

Common Development Patterns

Watching Reconciler Behavior

Run the operator with debug logging and watch what happens when resources change:

# Terminal 1: Run operator
go run ./cmd/operator/...

# Terminal 2: Create a resource and watch it
kubectl apply -f my-resource.yaml && kubectl get mykind -w
Forcing a Re-reconcile

The operator reconciles on changes. To force a re-reconcile without editing the resource:

# Touch the resource with a no-op annotation change
kubectl annotate mykind my-resource grafana.com/force-reconcile="$(date)" --overwrite
Checking Admission Webhooks

For standalone mode, the operator runs its own webhook server. Test admission by creating/updating resources and checking for validation errors:

# Invalid resource (should be rejected)
kubectl apply -f invalid-resource.yaml
# Output should include the admission error message

# Check webhook logs in the operator output
Resetting State

To start fresh during development:

# Delete all resources of a kind
kubectl delete mykind --all -n default

# Delete and re-apply CRDs (loses all data)
kubectl delete -f definitions/
kubectl apply -f definitions/

Both commands will produce an error for the <app>-manifest.(json|yaml) file, which is not a valid Kubernetes resource. These errors can be safely ignored.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

What our scanner noticed· Medium risk

  • References to credential files

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Grafana Labs
Publisher
Grafana Labs (Official)
Source
grafana/skills · skills/grafana-app-sdk/app-sdk-concepts · commit 8fb72a5
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Grafana Labs or Grafana Labs.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download app-sdk-concepts.zip