Loading...
Loading...
Use when: user asks to create a Grafana app, initialize a grafana-app-sdk project, set up a Grafana App Platform app, scaffold a new app, or asks about deployment modes (standalone operator, grafana/apps, frontend-only), how grafana-app-sdk works, or the overall development workflow. Provides foundational knowledge of the grafana-app-sdk CLI, project structure, deployment modes, and overall workflow.
npx skill4agent add grafana/skills app-sdk-conceptsgo install github.com/grafana/grafana-app-sdk/cmd/grafana-app-sdk@latestgrafana-app-sdk versiongithub.com/grafana/grafanaapps/pkg/registry/apps/| Mode | Description | Context |
|---|---|---|
| Standalone operator | Single binary, runs as a Kubernetes operator with its own webhook server | Outside Grafana repo |
| grafana/apps | Submodule inside | Inside Grafana repo only |
| Frontend-only | No backend code; CUE kinds and generated types only | Outside Grafana repo |
# 1. Initialize the project (use the Go module path)
grafana-app-sdk project init github.com/example/my-app
# 2. Add operator scaffolding (prompt the user before running)
grafana-app-sdk project component add operatorproject component add operatorapp.Appapps/pkg/registry/apps/# 1. Create the app subdirectory and init inside it
mkdir -p apps/my-app
cd apps/my-app
grafana-app-sdk project init github.com/grafana/grafana/apps/my-app
# 2. Clean up — keep ONLY these directories/files:
# kinds/ pkg/ go.mod go.sum
# Delete everything else generated by project init.
# 3. Copy the Makefile from apps/example (run from repo root)
cp apps/example/Makefile apps/my-app/Makefile
# 4. Copy the codegen config from apps/example (run from repo root) (ALWAYS OVERWRITE)
cp apps/example/kinds/config.cue apps/my-app/kinds/config.cue
# 5. Update the go workspace to use the new app
go work use ./apps/my-apppkg/registry/apps/apps.goProvideAppInstallersregister.gopkg/registry/apps/my-app/apps/example/README.mdgrafana-app-sdk project init github.com/example/my-app
# Skip operator and backend component scaffolding entirely
# Run generate to produce TypeScript types, then build frontend1. project init → scaffolds module, Makefile, kinds/ dir
2. project kind add → adds CUE kind scaffold to kinds/
3. Edit kinds/*.cue → define schemas, validation, versions
4. grafana-app-sdk generate → produces Go types, clients, TS types,
AppManifest, CRD files
5. Implement logic → fill in reconciler and admission stubs
6. (optional) add frontend → grafana-app-sdk project component add frontendmy-app/
├── cmd/
│ └── operator/ # Build target package for the operator, contains the `main` package
├── kinds/ # CUE kind definitions (source of truth)
│ ├── manifest.cue # App-level manifest and version declarations
│ ├── mykind.cue # kind metadata for MyKind
│ └── mykind_v1alpha1.cue # version schema for MyKind version v1alpha1
├── pkg/
│ ├── generated/ # Generated Go code — do NOT edit manually
│ ├── watchers/ # Watcher stubs generated by `project component add operator`
│ └── app/
│ └── app.go # Entry point; implement app.App interface here
├── definitions/ # Generated CRD and manifest files — do NOT edit manually
├── local/
│ ├── additional/ # Folder for specifying additional YAML manifests for local deployment
│ ├── generated/ # Folder where generated manifests for a local deployment live (don't commit)
│ ├── mounted-files/ # Folder that gets mounted to the k3d cluster (don't commit)
│ ├── scripts/ # Generated scripts (don't commit)
│ ├── Tiltfile # Tiltfile for standing up local resources
│ └── config.yaml # configuration file for local setup
├── go.mod
└── Makefileapp.Config.SpecificConfigregister.goNew// pkg/app/config.go
type AppSpecificConfig struct {
EnableReconciler bool
SomeFeatureFlag bool
}
// pkg/app/app.go — read it in New()
func New(cfg app.Config) (app.App, error) {
appCfg, _ := cfg.SpecificConfig.(*AppSpecificConfig)
if appCfg != nil && appCfg.EnableReconciler {
// wire up reconciler
}
// ...
}
// pkg/registry/apps/<name>/register.go — populate from Grafana config
specificConfig := &app.AppSpecificConfig{
EnableReconciler: features.IsEnabled(featuremgmt.FlagMyAppReconciler),
}
provider := simple.NewAppProvider(manifestdata.LocalManifest(), specificConfig, app.New)SpecificConfigNew# Project management
grafana-app-sdk project init <module>
grafana-app-sdk project kind add <KindName> --overwrite
grafana-app-sdk project component add operator
grafana-app-sdk project component add frontend
# Code generation
grafana-app-sdk generate