App SDK Concepts
Grafana LabsOfficialPublished by Grafana Labs
- Skill
- Tool integration
- Cloud and DevOps
- Apache-2.0
- Medium risk
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
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/grafana/app-sdk-concepts/downloadUnzip 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 # verifyCommon 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.goCommon 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-appThen 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 frontendAlways rerun generate after every CUE change — generated code is the API your reconciler sees.
Deployment modes (one-line table)
| Mode | When to pick | Where it runs |
|---|---|---|
| Standalone operator | Outside Grafana repo, want your own binary | Kubernetes operator with its own webhook server |
| grafana/apps | Inside github.com/grafana/grafana (or fork) | In-process inside Grafana's API server |
| Frontend-only | UI-only app, no Go logic needed | No backend — TS types only |
Full per-mode init, runtime, and wiring detail in references/deployment-modes.md.
References
references/deployment-modes.md— per-mode init, runtime semantics, grafana/apps registration walkthroughreferences/project-structure.md— standalone project layout, what's hand-edited vs generatedreferences/cli-reference.md— everygrafana-app-sdksubcommand with flagsreferences/specific-config.md—app.Config.SpecificConfigpattern for feature-flag-driven app configreferences/local-development.md— Tilt + k3d local dev loopreferences/local-config.md—local/config.yamlreference
Resources
Files
- ATTRIBUTION.mdAdded by AutoGineer855 B
- LICENSELicence file added by AutoGineer11.1 KiB
- SKILL.md4.3 KiB
- references/cli-reference.md8.6 KiB
- references/deployment-modes.md5.4 KiB
- references/local-config.md4.2 KiB
- references/local-development.md6.5 KiB
- references/project-structure.md1.6 KiB
- references/specific-config.md975 B
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-filesand a YAML bundle in./local/generated/dev-bundle.yaml../local/scripts/cluster.sh create "local/generated/k3d-config.json"to create the clustertilt upin thelocaldirectory 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-resourceDebug 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 nodesApply 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 runYour app is automatically included in the binary because it's registered in pkg/registry/apps/apps.go.
Testing with Grafana UI
Navigate to
http://localhost:3000Use the Grafana API or UI to create resources of your kind
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/mykindsCommon 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 -wForcing 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)" --overwriteChecking 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 outputResetting 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.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download app-sdk-concepts.zip