Skip to main content

Backend architecture

Grafana’s backend is written in Go and follows a clean, service-oriented architecture with compile-time dependency injection.

Directory structure

The backend code lives in pkg/ and is organized by concern:

Dependency injection with Wire

Grafana uses Google Wire for compile-time dependency injection, providing type safety and circular dependency detection.

Wire configuration

The main Wire configuration is in pkg/server/wire.go:
Key Wire patterns used in pkg/server/wire.go:
  • Provider functions - Functions like ProvideService() that return initialized services
  • Wire sets - Groups of related providers (wireBasicSet, withOTelSet)
  • Interface bindings - wire.Bind() to bind implementations to interfaces
  • Injector functions - Initialize() functions that Wire generates implementations for

Regenerating Wire code

After modifying service initialization or dependencies:
This generates pkg/server/wire_gen.go with the actual initialization code. Common Wire patterns:

Service layer architecture

Services contain business logic and are organized by domain.

Service structure

Typical service structure in pkg/services/<domain>/:

Service interface pattern

Services implement interfaces defined in the same package:
Key principles:
  • Interfaces in the package root, implementations in service/ or implementation-specific subdirectories
  • Business logic in services, not in API handlers
  • Services depend on other services through interfaces
  • Data access through repository/store patterns

API handlers

HTTP API handlers live in pkg/api/ and delegate to services.

API structure

API handler responsibilities:
  • Request parsing and validation
  • Authentication/authorization checks
  • Calling service methods
  • Response formatting
  • Error handling

Routing

Routes are registered in pkg/api/api.go:

Database access

Database access is handled through the sqlstore package.

SQLStore

The main database interface is pkg/services/sqlstore/sqlstore.go:
Database patterns:
  • XORM for ORM
  • Raw SQL for complex queries
  • Transactions via WithDbSession or WithTransactionalDbSession
  • Migration system in pkg/services/sqlstore/migrations/

Example repository

Plugin backend system

Backend plugins run as separate processes and communicate via gRPC.

Plugin structure

From pkg/plugins/plugins.go:

Plugin loading

Plugins are discovered and loaded through a pipeline:
  1. Discovery - Find plugin directories
  2. Validation - Check signatures and compatibility
  3. Initialization - Load plugin.json, start backend process
  4. Registration - Register with plugin registry
See pkg/plugins/manager/pipeline/ for pipeline implementation.

Data source query system

Data source backends live in pkg/tsdb/:
Each data source implements the backend.QueryDataHandler interface.

Infrastructure services

Logging

Metrics

Prometheus metrics via pkg/infra/metrics/:

Tracing

OpenTelemetry tracing via pkg/infra/tracing/:

Server initialization

The server starts in pkg/server/server.go:
  1. Load configuration from conf/defaults.ini and conf/custom.ini
  2. Initialize database connection and run migrations
  3. Wire builds the dependency graph
  4. Start HTTP server
  5. Start background services

Testing patterns

Unit tests

Integration tests

Integration tests use real databases (SQLite, PostgreSQL, MySQL) via Docker.

Key patterns summary

  • Wire DI - Compile-time dependency injection for type safety
  • Service interfaces - Business logic behind interfaces
  • Thin handlers - API handlers delegate to services
  • Repository pattern - Data access abstraction
  • Plugin architecture - Extensibility via gRPC
  • Migration system - Database schema versioning