Grafana — Structure#

Layout pattern#

Monorepo (custom multi-language, multi-module)

Grafana does not follow the standard cmd/internal/pkg Go layout. Instead it is a true polyglot monorepo with a Go backend under pkg/, a TypeScript/React frontend under public/, standalone App SDK Go modules under apps/, Yarn workspace packages under packages/, CUE schemas under kinds/, and ~35 Go modules all managed by a root go.work file. This is a custom layout evolved for enterprise-scale, with no single idiomatic Go convention dominating.

Directory map#

grafana/
├── apps/               # Standalone Grafana App SDK apps (each is its own Go module)
│   ├── advisor/        # Health/configuration advisor app
│   ├── alerting/       # Alerting sub-apps (enrichment, historian, notifications, rules)
│   ├── dashboard/      # Dashboard resource app
│   ├── folder/         # Folder resource app
│   ├── iam/            # Identity & access management app
│   ├── plugins/        # Plugin management app
│   ├── provisioning/   # Provisioning app (GitHub-backed)
│   └── ...             # ~20 other domain apps
├── conf/               # Default configuration (defaults.ini, provisioning examples)
├── contribute/         # Contributor guides (architecture docs, backend/frontend style)
├── cue.mod/            # CUE module definition for schema generation
├── devenv/             # Local dev environment (Docker compose, dashboards, scripts)
├── docs/               # End-user documentation source (served by Grafana website)
├── e2e/                # Cypress end-to-end test suites
├── e2e-playwright/     # Playwright end-to-end test suites
├── emails/             # Email notification templates
├── kinds/              # CUE schema definitions → generates Go + TypeScript types
├── kindsv2/            # Next-gen CUE schema definitions
├── packages/           # Frontend Yarn workspace packages (@grafana/data, ui, runtime…)
├── packaging/          # Linux (deb/rpm), macOS, Docker packaging scripts
├── pkg/                # Go backend source code (primary Go module)
│   ├── aggregator/     # API aggregation layer (Kubernetes-style)
│   ├── api/            # HTTP API handlers, routes, DTOs
│   ├── apimachinery/   # Kubernetes API machinery abstractions
│   ├── apis/           # Kubernetes-style API group registrations
│   ├── apiserver/      # Embedded kube-apiserver support
│   ├── build/          # Build tooling Go code (Dagger pipelines, e2e runners)
│   ├── bus/            # In-process event bus
│   ├── cmd/            # Binary entry points (grafana, grafana-cli, grafana-server)
│   ├── codegen/        # Go code generation tooling
│   ├── components/     # Shared utility components (simplejson, imguploader, etc.)
│   ├── expr/           # Server-side expression evaluation (math, classic conditions)
│   ├── generated/      # Generated Kubernetes client/informer/lister code
│   ├── infra/          # Cross-cutting infrastructure (logging, metrics, DB, caching)
│   ├── kinds/          # CUE-generated Go types for Grafana kinds
│   ├── middleware/      # HTTP middleware (auth, CSRF, logging, rate limiting)
│   ├── mocks/          # Shared mock implementations
│   ├── models/         # Legacy shared domain model types
│   ├── modules/        # Module lifecycle management
│   ├── operators/      # Kubernetes operator extensions
│   ├── plugins/        # Plugin system (loader, gRPC backend, registry)
│   ├── registry/       # API and service registries
│   ├── server/         # Server initialization, Wire DI wiring
│   ├── services/       # Business logic organized by domain (~60 sub-packages)
│   ├── setting/        # Configuration management (INI-based)
│   ├── storage/        # Unified storage abstraction layer
│   ├── tests/          # Integration test helpers
│   ├── tsdb/           # Time series data source query backends (per data source)
│   └── util/           # General utilities
├── public/             # Frontend assets (TypeScript/React, SASS, images)
│   ├── app/            # React application (features/, core/, plugins/, store/)
│   └── ...             # Static assets (fonts, maps, swagger, views)
├── scripts/            # Build/CI shell scripts, code generation helpers
└── tools/              # Developer tooling

Entry points#

BinaryPathPurpose
grafanapkg/cmd/grafana/main.goUnified binary; hosts server and cli as subcommands via urfave/cli/v2
grafana serverpkg/cmd/grafana-server/commands/Starts the Grafana HTTP server and all backend services
grafana clipkg/cmd/grafana-cli/commands/Plugin management CLI (install, update, list plugins)

The single grafana binary is the modern entry point (combining what were previously two separate binaries). An optional third command — the standalone API server — is injected at startup if server.InitializeAPIServerFactory() succeeds, enabling a Kubernetes-style API server mode.

Package organization#

  • Internal packages: All backend code lives under pkg/ but most packages are directly importable — there is no root-level internal/ boundary. The few internal/ subdirs (e.g. within individual services) enforce package-level encapsulation. Key sub-areas:

    • pkg/infra/ — Infrastructure primitives: logging (log), metrics, database (db), tracing, caching (remotecache, localcache), kvstore, httpclient, feature flags
    • pkg/services/ — ~60 domain service packages (alerting/ngalert, dashboards, users, auth, LDAP, SCIM, secrets, etc.). Each service package typically defines its interface in the same package and provides one or more implementations.
    • pkg/plugins/ — Plugin lifecycle: discovery, loading, signature verification, gRPC backend communication, plugin registry
    • pkg/tsdb/ — One sub-package per data source backend (cloudwatch, azuremonitor, cloud-monitoring, elasticsearch, etc.)
    • pkg/api/ — HTTP handlers and route registration; handlers delegate to services
    • pkg/server/ — Application bootstrap; Wire DI wiring files (wire.go, wire_gen.go)
    • pkg/apiserver/ + pkg/apis/ + pkg/aggregator/ — Kubernetes API server embedding for the new API layer
    • pkg/expr/ — Server-side expression evaluation engine
    • pkg/setting/ — INI-based configuration loading and hot-reload
  • Public packages (pkg/): No explicit pkg/ boundary in the classic sense — the Go module root is github.com/grafana/grafana and most packages under pkg/ are importable. The sub-modules listed in go.work (e.g. pkg/apimachinery, pkg/apiserver, pkg/plugins) are explicitly published as separate modules for use by the Grafana App SDK ecosystem.

  • apps/ modules: ~20 standalone Go modules using the Grafana App SDK pattern. Each app is a self-contained resource API (e.g. apps/dashboard, apps/folder, apps/alerting/rules). They are included in go.work but independently versioned and can be tested in isolation.

  • Layering: The project follows a loose layered architecture:

    1. Infrastructure (pkg/infra/) — no domain knowledge
    2. Services (pkg/services/) — business logic, depend on infra and each other via interfaces
    3. API handlers (pkg/api/) — HTTP layer, depend on services
    4. Server (pkg/server/) — wires everything together at startup

    This is enforced by convention rather than Go’s internal/ mechanism. Wire provides compile-time validation of the dependency graph.

Build system#

  • Build tool: GNU Make (Makefile) as the primary orchestrator; delegates to Go toolchain, Yarn, and Dagger
  • Key targets:
    • make build-backend — Compiles ./bin/<OS>/<ARCH>/grafana from ./pkg/cmd/grafana
    • make run — Backend hot-reload via air
    • make test-go-unit / make test-go-integration — Backend test suites
    • make gen-go — Regenerates Wire DI (wire_gen.go) after service changes
    • make gen-cue — Regenerates Go + TS types from CUE schemas in kinds/
    • make gen-apps — Generates App SDK app scaffolding
    • make swagger-gen — Regenerates OpenAPI/Swagger specifications
    • make gen-feature-toggles — Regenerates feature flag code from definitions
    • make devenv — Starts backing services (Postgres, InfluxDB, Loki, etc.) via Docker Compose
  • Frontend build: Yarn 4 (via corepack) with webpack. yarn start for dev server, yarn build for production.
  • Docker: Yes, multi-stage (Dockerfile). Stages: go-builder-base (golang:1.26.1-alpine), js-builder-base (node:24-alpine), alpine-base, ubuntu-base. The final image is minimal Alpine. Uses BuildKit syntax (dockerfile:1.7-labs).
  • CI: Dagger-based pipeline (pkg/build/daggerbuild/) for reproducible builds; test sharding via SHARD/SHARDS env vars.
  • Go workspace: go.work manages 35+ Go modules. Run make update-workspace after adding modules.

Notable structural decisions#

  1. Single unified binary with subcommands: What were historically two binaries (grafana-server and grafana-cli) are now a single grafana binary with server and cli as top-level subcommands. A third subcommand (standalone API server) is conditionally injected if enterprise features are available — the same binary can run as a full monolith or a Kubernetes API server.

  2. go.work multi-module workspace: Grafana manages 35+ Go modules in a single workspace. Modules like pkg/apimachinery, pkg/apiserver, pkg/plugins, and all apps/ are independently versioned and published (used by the external Grafana App SDK), yet developed in a unified workspace with local replace directives handled automatically by go.work.

  3. Wire-generated dependency injection at 1939-line scale: pkg/server/wire_gen.go (1939 lines, generated) wires together hundreds of services. The human-authored wire.go uses //go:build wireinject to stay separate from the generated file. OSS vs. enterprise variants are separated into wireexts_oss.go / wireexts_enterprise.go with build tags (oss, enterprise).

  4. apps/ as the future architectural direction: The apps/ directory represents Grafana’s migration toward the App SDK pattern — each domain resource (dashboard, folder, alerting) becomes a standalone Kubernetes-style app with its own Go module, API types, and storage handlers. This is being phased in alongside the legacy pkg/services/ approach.

  5. CUE as the schema source of truth: Dashboard and panel type schemas live in kinds/ as CUE definitions and drive code generation in both directions: make gen-cue emits Go structs into pkg/kinds/ and TypeScript types into packages/grafana-schema/. This eliminates manual frontend/backend type synchronization for any Grafana-native resource type.

  6. pkg/tsdb/ as a data source plugin repository: Core data source backends (CloudWatch, Azure Monitor, Google Cloud Monitoring, Elasticsearch, etc.) live in pkg/tsdb/ as Go packages inside the monorepo. Each has its own standalone/ subdirectory for running as an independent gRPC plugin binary — the same code can run embedded or as an external process.