Overview
Relevant Files
README.mdpkg/README.mdpackages/README.mdcontribute/README.mdcontribute/backend/README.mdcontribute/architecture/README.md
Grafana is an open-source platform for monitoring and observability. It enables users to query, visualize, alert on, and understand metrics from any data source. The codebase is organized into backend (Go) and frontend (TypeScript/React) components, with a modular architecture designed for extensibility through plugins.
What is Grafana?
Grafana provides a comprehensive observability platform with several core capabilities:
- Visualizations: Fast, flexible client-side graphs with numerous panel types and customization options
- Dynamic Dashboards: Reusable dashboards with template variables for dynamic filtering
- Data Exploration: Ad-hoc queries with split-view comparisons across time ranges and data sources
- Alerting: Visual alert rule definition with notifications to Slack, PagerDuty, OpsGenie, and other systems
- Multi-Source Support: Mix different data sources in the same visualization with per-query source selection
Repository Structure
The Grafana repository follows a clear separation between backend and frontend:
grafana/
├── pkg/ # Go backend code
│ ├── api/ # HTTP API endpoints
│ ├── services/ # Core services (auth, storage, plugins, etc.)
│ ├── models/ # Domain models and data structures
│ ├── storage/ # Unified storage layer for resources
│ ├── plugins/ # Plugin system and management
│ └── ...
├── public/ # Frontend assets and code
│ ├── app/ # React application code
│ │ ├── core/ # Core services and utilities
│ │ ├── features/ # Feature modules (dashboards, alerting, etc.)
│ │ └── plugins/ # Plugin integration
│ └── build/ # Compiled frontend assets
├── packages/ # Reusable frontend packages
│ ├── grafana-ui/ # UI component library
│ ├── grafana-data/ # Data utilities and types
│ ├── grafana-runtime/ # Runtime utilities
│ └── ...
└── contribute/ # Contribution guidelines
├── backend/ # Backend development guides
└── architecture/ # Architecture documentation
Backend Architecture
The backend is written in Go and organized by feature domains. Key architectural patterns include:
Service-Oriented Design: Services encapsulate business logic and are registered with a service registry. Each service manages its own lifecycle (initialization, running, shutdown) through the dskit module system.
Unified Storage: A Kubernetes-inspired resource API layer (/apis/...) provides declarative, eventually-consistent resource management. This complements the traditional Legacy API (/api/...) and uses a unified storage backend that can persist to SQL databases (PostgreSQL, MySQL, SQLite).
Plugin System: Grafana supports backend plugins through a plugin framework. Plugins can implement data source queries, alerting rules, and custom resource handlers.
Package Hierarchy: Packages are organized by feature with clear ownership. Domain types and interfaces live in root packages, while implementation details (HTTP handlers, database queries) are in subpackages.
Frontend Architecture
The frontend is a React application built with TypeScript, organized into modular features:
Core Services: Global services like BackendSrv (HTTP communication), LocationService (routing), and KeybindingSrv (keyboard shortcuts) are provided through React Context.
Feature Modules: Features like dashboards, alerting, and data exploration are self-contained modules with their own components, services, and state management.
Reusable Packages: The packages/ directory contains shared libraries published to npm:
@grafana/ui- UI component library@grafana/data- Data utilities and types@grafana/runtime- Runtime utilities for plugins@grafana/schema- Type definitions for Grafana resources
Plugin Integration: Plugins are loaded dynamically and can extend Grafana's functionality through extension points and custom panels.
Key Technologies
Backend: Go, PostgreSQL/MySQL/SQLite, gRPC, REST APIs
Frontend: React, TypeScript, Redux (state management), Webpack (bundling)
Build System: Make, Dagger (containerized builds), Lerna (package management)
Testing: Jest (frontend), Go testing (backend), Playwright (E2E)
Development Workflow
The repository uses a monorepo structure with:
- Lerna for managing frontend packages and versioning
- Go workspaces for managing backend modules
- Makefile for common build and development tasks
- Docker Compose for local development environments with databases and data sources
Contributors should start with the Developer guide and relevant style guides for backend or frontend work.
Architecture & System Design
Relevant Files
contribute/architecture/README.mdcontribute/backend/README.mdcontribute/backend/package-hierarchy.mdcontribute/backend/services.mdpkg/server/wire.gopkg/server/server.gocontribute/architecture/k8s-inspired-backend-arch.md
Grafana's architecture combines a modular backend service layer with a Kubernetes-inspired resource API model, enabling both traditional REST endpoints and declarative resource management.
Backend Service Architecture
Grafana uses Wire, a code generation tool for dependency injection, to wire services together. Each service encapsulates related business logic and exposes it through well-defined interfaces.
Service Structure:
Services follow a consistent pattern with three key components:
- Root package (
pkg/services/servicename/): Contains interfaces, domain types, and errors that other services depend on - Implementation package (
pkg/services/servicename/serviceimpl/): Houses the concrete service implementation and storage logic - Test doubles (
pkg/services/servicename/servicenametest/): Provides fakes and mocks for testing
Each service has a ProvideService factory method that Wire uses to resolve dependencies and initialize the service. Services can implement optional interfaces like registry.BackgroundService to run background tasks or registry.CanBeDisabled to support conditional initialization.
func ProvideService(cfg *setting.Cfg, db db.DB) (*Service, error) {
s := &Service{cfg: cfg, db: db}
if err := s.init(); err != nil {
return nil, err
}
return s, nil
}
Package Hierarchy
Grafana organizes packages by feature rather than by layer. This approach reduces circular dependencies and improves maintainability:
- Domain types and interfaces stay in root packages to minimize coupling
- Sub-packages depend on roots, not vice versa, preventing circular imports
- Storage is abstracted behind interfaces, allowing multiple implementations
- Migrations and API endpoints remain centralized in
pkg/services/sqlstore/migrationsandpkg/api/respectively
Dual API Model: Legacy and Resource APIs
Grafana is transitioning from traditional REST endpoints (/api/...) to Kubernetes-inspired Resource APIs (/apis/...). Both coexist during migration.
Legacy APIs (/api/...):
- Variable URL structures and response formats
- Implicit organization context (via session or API key)
- Feature-specific implementations
Resource APIs (/apis/...):
- Kubernetes-style paths:
/apis/group/version/namespaces/namespace/resource/name - Explicit versioning (v1alpha1, v1beta1, v1) in the URL
- Standardized schemas with OpenAPI specs
- Unified storage backend
Unified Storage and Resource Persistence
The Unified Storage layer (pkg/storage/unified/...) decouples Resource API handlers from storage backends. It implements Kubernetes' storage.Interface, translating Kubernetes operations to Grafana's resource client.
Key features:
- Resource versioning: Each resource has a
resourceVersionthat changes on modification, enabling optimistic concurrency control - Watch support: Efficient change detection via
resource_historytable, even on standard SQL databases - Multiple backends: Supports SQL databases (PostgreSQL, MySQL, SQLite), file storage, and remote gRPC storage
API Implementation Approaches
Registry Approach (pkg/registry/apis/...):
- Go-based API definitions using
register.gofiles - Direct implementation of REST handlers
- Used for legacy fallbacks and infrastructure APIs
Apps Approach (apps/...):
- Modern, modular implementation using CUE schemas
- Self-contained apps with versioning and dependencies
- Generates Go types and supports controllers/reconcilers
- Preferred pattern for new resources
Loading diagram...
Server Initialization and Lifecycle
The Server struct manages Grafana's lifecycle from startup to shutdown. Wire generates wire_gen.go which instantiates all services with their dependencies resolved. The server then:
- Initializes all services via Wire-generated code
- Registers background services with the registry
- Starts HTTP server and background service runners
- Manages graceful shutdown
Services can be disabled conditionally via the IsDisabled() method, and background services run concurrently during server operation.
Backend Services & APIs
Relevant Files
pkg/api/api.gopkg/api/http_server.gopkg/services/dashboardspkg/services/datasourcespkg/services/ngalertpkg/services/authpkg/services/querypkg/services/apiserver
Architecture Overview
Grafana's backend is organized around a service-oriented architecture where the HTTP API layer (pkg/api) routes requests to specialized services. The main entry point is the HTTPServer in http_server.go, which registers all API routes and manages the lifecycle of backend services.
Loading diagram...
Core API Layer
The API layer in pkg/api/api.go defines all HTTP endpoints and middleware chains. Routes are registered using a fluent builder pattern through the RouteRegister interface. Key route groups include:
- Authentication: Login, logout, OAuth flows
- User Management: User profiles, organizations, teams
- Dashboards: CRUD operations, permissions, snapshots
- Datasources: Configuration, validation, proxy
- Alerting: Alert rules, notification policies, silences
- Search: Dashboard and user search with sorting
Middleware is applied at multiple levels: global (CSRF, logging), group-level (authentication), and route-level (authorization, quotas).
Service Architecture
Each major feature area has a dedicated service package under pkg/services/. Services follow a consistent pattern:
Dashboards Service (pkg/services/dashboards) handles dashboard persistence, versioning, and access control. It provides methods for creating, updating, deleting, and querying dashboards with full audit trails.
Datasources Service (pkg/services/datasources) manages datasource configurations, caching, and validation. It includes a guardian system for access control and supports dynamic datasource discovery.
Query Service (pkg/services/query) orchestrates query execution across multiple datasources. It parses requests, routes queries to appropriate datasources, handles expressions, and manages concurrent query execution with configurable limits.
Alerting Service (pkg/services/ngalert) implements unified alerting with rule evaluation, notification routing, and state management. It supports multiple notification backends and integrates with external alertmanagers.
Auth Services (pkg/services/auth, pkg/services/authn) handle authentication and identity management, supporting multiple auth methods (basic, OAuth, LDAP, SAML).
Query Execution Flow
The query service processes requests through several stages:
- Parsing: Requests are parsed into queries grouped by datasource UID
- Validation: Datasource access is validated using the guardian system
- Routing: Queries are routed to appropriate handlers:
- Single datasource queries execute directly
- Multi-datasource queries execute concurrently with configurable limits
- Expression queries are handled by the expression service
- Execution: Queries are sent to datasource plugins via the plugin client
- Response Aggregation: Results are combined and returned to the caller
API Server Integration
The newer pkg/services/apiserver provides Kubernetes-style API server capabilities for modern resource management. It supports dual-write patterns for gradual migration from legacy APIs and includes built-in authorization, audit logging, and resource versioning.
Key Design Patterns
Dependency Injection: Services are wired together using Wire, with all dependencies explicitly declared in provider functions.
Interface-Based Design: Services expose interfaces for testability and loose coupling.
Middleware Chains: HTTP middleware is composed using functional wrappers for cross-cutting concerns.
Access Control: Fine-grained permissions are enforced through the AccessControl service with role-based and resource-based policies.
Frontend Architecture & State Management
Relevant Files
public/app/core/store.tspublic/app/store/configureStore.tspublic/app/core/reducers/root.tspublic/app/core/context/GrafanaContext.tspublic/app/store/store.tspublic/app/types/store.tscontribute/architecture/frontend-data-requests.md
Grafana uses a layered state management architecture combining Redux for global application state, React Context for service injection, and RTK Query for server state caching. This design enables predictable state updates, efficient data fetching, and clean separation of concerns.
Redux Store Architecture
The Redux store is configured in configureStore.ts using Redux Toolkit. The root reducer combines domain-specific reducers from features like dashboards, alerting, datasources, and variables. The store is initialized with middleware including thunks, RTK Query APIs, and custom listener middleware for side effects.
const store = reduxConfigureStore({
reducer: createRootReducer(),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ thunk: true }).concat(
listenerMiddleware.middleware,
alertingApi.middleware,
publicDashboardApi.middleware,
// ... other API middlewares
),
devTools: process.env.NODE_ENV !== 'production',
});
The root reducer in root.ts aggregates reducers from all features. New reducers can be added dynamically via addReducer() before store initialization. This modular approach keeps feature state isolated while maintaining a single source of truth.
GrafanaContext for Service Injection
GrafanaContext provides access to core services without prop drilling. It includes BackendSrv for HTTP requests, LocationService for routing, AppChromeService for UI chrome management, and KeybindingSrv for keyboard shortcuts. Components access these via the useGrafana() hook.
export interface GrafanaContextType {
backend: BackendSrv;
location: LocationService;
config: GrafanaBootConfig;
chrome: AppChromeService;
keybindings: KeybindingSrv;
newAssetsChecker: NewFrontendAssetsChecker;
}
Data Fetching Patterns
RTK Query is the modern approach for server state. It provides automatic caching, request deduplication, and background refetching. APIs are defined using createApi() with a custom base query that wraps BackendSrv.fetch().
export const alertingApi = createApi({
reducerPath: 'alertingApi',
baseQuery: backendSrvBaseQuery(),
endpoints: (builder) => ({
getAlertRules: builder.query({...}),
}),
});
BackendSrv handles all HTTP requests with built-in request queuing and cancellation. It uses RxJS Observables for reactive request handling and supports request deduplication via requestId.
Thunks are used for legacy features. They dispatch actions to update Redux state after async operations complete.
Request Management
Grafana limits parallel data source requests to 5 (or 1000 with HTTP/2) to prevent browser connection limits from blocking interactions. Requests can be canceled by requestId or via RxJS subscription cleanup. The request queue ensures API requests always have a free slot.
Component State Patterns
Local component state uses React hooks (useState, useReducer). Complex query editors use local reducer contexts (e.g., Elasticsearch, Graphite) to manage editor state independently. Global state is accessed via useSelector() and useDispatch() from Redux, or RTK Query hooks like useGetAlertRulesQuery().
const { data, isLoading, error } = useGetAlertRulesQuery(params);
Typed Hooks
public/app/types/store.ts exports typed versions of Redux hooks: useDispatch(), useSelector(), and createAsyncThunk(). These provide full TypeScript support for store state and dispatch actions, reducing runtime errors.
Datasources & Plugin System
Relevant Files
pkg/tsdb- Built-in datasource implementations (Prometheus, Loki, CloudWatch, etc.)pkg/plugins- Core plugin system and lifecycle managementpkg/services/datasources- Datasource service, storage, and cachingpkg/services/pluginsintegration- Plugin integration layer with Grafana servicespublic/app/plugins/datasource- Frontend datasource plugin implementationspackages/grafana-schema/src- Plugin and datasource schema definitions
Overview
Grafana's datasource and plugin system provides a modular architecture for extending functionality. Datasources enable querying external data systems, while plugins extend Grafana with new visualizations, data sources, and applications. Both systems share a common plugin infrastructure with discovery, loading, validation, and lifecycle management.
Datasource Architecture
Datasources are specialized plugins that connect Grafana to external data systems. Each datasource has two components:
Backend Implementation - Handles query execution and data retrieval. Located in pkg/tsdb/, built-in datasources like Prometheus, Loki, and CloudWatch implement the QueryDataHandler interface to process queries and return data frames.
Frontend Implementation - Provides UI components for query building and configuration. Located in public/app/plugins/datasource/, these implement the DataSourceApi interface to handle query requests and return observable responses.
Datasources are registered with the system through the datasource service (pkg/services/datasources/service/datasource.go), which manages CRUD operations, caching, and access control. The service stores datasource configurations in the database and handles secret encryption for sensitive credentials.
Query Execution Flow
When a dashboard executes a query, the flow follows these steps:
-
Request Parsing - The query service (
pkg/services/query/query.go) receives the request and parses it into queries grouped by datasource UID. -
Routing - Single datasource queries are routed directly to the plugin. Multi-datasource queries are executed concurrently. Expression queries are handled by the expression service.
-
Plugin Invocation - The plugin client calls the datasource's
QueryDatamethod via gRPC (for external plugins) or directly (for core plugins). The request includes the plugin context with authentication and datasource settings. -
Response Aggregation - Results are collected and returned as a
QueryDataResponsecontaining data frames keyed by RefID.
Frontend Request
↓
Query Service (parseMetricRequest)
↓
Route by datasource count
├→ Single DS: handleQuerySingleDatasource
├→ Multiple DS: executeConcurrentQueries
└→ Expressions: handleExpressions
↓
Plugin Client (QueryData)
↓
Backend Plugin (QueryDataHandler)
↓
Data Frames Response
Plugin System Architecture
Grafana supports four plugin types:
Datasource - Connects to external data systems. Implements query execution and health checks. Examples: Prometheus, PostgreSQL, CloudWatch.
Panel - Visualizes data on dashboards. Implements rendering logic and configuration UI. Examples: Time Series, Stat, Geomap.
App - Bundles datasources, panels, and custom pages into a cohesive experience. Can add navigation and custom UI routes.
Renderer - Handles image rendering for dashboards and alerts. Typically runs as an external process.
Plugin Lifecycle
The plugin loader (pkg/plugins/manager/loader/loader.go) manages plugins through five stages:
Loading diagram...
Discovery - Scans plugin directories and identifies plugin bundles. Reads plugin.json manifests.
Bootstrap - Constructs plugin objects, resolves dependencies, and prepares assets. Sets up module URLs and base paths for frontend loading.
Validation - Verifies plugin signatures and checks for security issues. Unsigned plugins may be blocked based on configuration.
Initialization - Starts backend clients (gRPC for external plugins), registers action sets, and reports metrics.
Termination - Gracefully stops plugins and cleans up resources.
Plugin Registration and Discovery
Plugins are discovered from configured directories and registered with the plugin registry. The registry maintains metadata about all loaded plugins, including:
- Plugin ID, type, and version
- Signature status and signing organization
- Module URL and loading strategy
- Configuration pages and extensions
- Backend capabilities (QueryData, CheckHealth, CallResource, etc.)
Frontend plugins are loaded dynamically using SystemJS. The loading strategy determines whether plugins are loaded eagerly or lazily. Core plugins are bundled with Grafana, while external plugins are loaded from the filesystem or CDN.
Backend Plugin Interface
Backend plugins implement handlers for different operations:
Plugin Interface
├── QueryDataHandler - Execute queries and return data
├── CheckHealthHandler - Verify datasource connectivity
├── CallResourceHandler - Handle custom API endpoints
├── StreamHandler - Support streaming data
├── AdmissionHandler - Validate resource changes
└── ConversionHandler - Convert between API versions
External plugins communicate with Grafana via gRPC using the plugin SDK. Core plugins are compiled directly into Grafana and called in-process.
Datasource Configuration and Secrets
Datasource configurations are stored in the database with the following structure:
- Name - User-friendly identifier
- Type - Plugin ID (e.g.,
prometheus,loki) - URL - Connection endpoint
- JSONData - Plugin-specific configuration (stored as JSON)
- SecureJsonData - Encrypted sensitive data (API keys, passwords)
The secrets service encrypts sensitive fields before storage and decrypts them on retrieval. Access control policies determine which users can query or modify datasources.
Runtime Datasources
Grafana supports registering datasources at runtime through the registerRuntimeDataSource API. This enables dynamic datasource creation without database persistence, useful for:
- Temporary datasources created by plugins
- Datasources derived from other datasources
- Expression datasources for query transformations
Runtime datasources are stored in memory and are not persisted across restarts.
Plugin Extensions
Plugins can expose and consume extensions through the plugin extension system. This allows:
- Panels to expose custom components for use in other plugins
- Datasources to provide custom query editors
- Apps to add navigation items and custom pages
Extensions are registered during plugin initialization and discovered by other plugins at runtime.
Frontend Packages & UI Components
Relevant Files
packages/grafana-uipackages/grafana-datapackages/grafana-runtimepackages/grafana-alertingpackages/grafana-prometheuspackages/grafana-api-clients
Grafana's frontend is built on a modular package architecture that separates concerns into reusable, independently versioned libraries. These packages form the foundation for both Grafana core and plugin development.
Core Packages Overview
@grafana/ui is the primary component library containing 100+ React components organized by category: forms (Input, Select, Combobox, Checkbox), buttons (Button, IconButton, ToolbarButton), visualizations (Gauge, BarGauge, BigValue, Sparkline), modals and overlays (Modal, Drawer, Tooltip, Popover), tables (Table, InteractiveTable), and layout utilities (Box, Stack, Grid). Components use Emotion for styling and follow the Saga Design System. All components are documented in Storybook with interactive examples.
@grafana/data provides core data types and utilities: DataFrames (columnar data structures), field types, transformations, value formatters, and query result handling. It includes utilities for time series processing, geospatial data, and field matching. This package has no React dependencies, making it suitable for backend-agnostic data processing.
@grafana/runtime bridges plugins and Grafana core, exporting services (BackendSrv, LocationService, KeybindingSrv), components (PanelRenderer, PanelDataErrorView), and utilities for query execution. It provides the plugin API surface and handles communication with the backend.
@grafana/alerting (Alpha) contains alerting-specific components and utilities: notification policies, label matchers, alert rules UI, and RTK Query API clients for the alerting system. It's designed for building alerting integrations and custom alerting solutions.
@grafana/prometheus exports Prometheus datasource components: PromQueryEditorByApp, MetricsBrowser, PromCheatSheet, and configuration editors. It includes query builders, exemplar fields, and variable query editors for Prometheus-specific functionality.
@grafana/api-clients (Beta) provides auto-generated RTK Query clients for Grafana APIs, enabling type-safe frontend-backend communication. Clients are generated from OpenAPI specifications.
Package Dependencies
@grafana/ui
├── @grafana/data
├── @grafana/i18n
├── @grafana/schema
└── React 18+
@grafana/runtime
├── @grafana/data
├── @grafana/ui
├── @grafana/schema
└── React 18+
@grafana/alerting
├── @grafana/data
├── @grafana/runtime
├── @grafana/ui
└── @grafana/api-clients
Export Patterns
All packages use conditional exports in package.json to support multiple entry points: the main export (.), unstable features (./unstable), and internal APIs (./internal). The internal export is stripped during npm publishing, preventing external packages from accessing private code while allowing Grafana core to use it.
Development Workflow
Packages are built with TypeScript and Rollup, generating CommonJS, ESM, and type declaration outputs. Storybook serves as the interactive documentation and testing environment for UI components. Each package maintains its own tsconfig.json and build configuration, enabling independent development and versioning.
Apps & Feature Modules
Relevant Files
apps/- Backend apps using Grafana App SDKapps/dashboard/- Dashboard management appapps/alerting/- Alerting subsystem (rules, notifications, historian)apps/folder/- Folder management appapps/iam/- Identity and access management appapps/provisioning/- Resource provisioning apppublic/app/features/- Frontend feature modulespkg/registry/apps/- App registration and initialization
Grafana is organized into modular apps and feature modules that handle distinct responsibilities. This architecture enables independent development, versioning, and deployment of core functionality.
Backend Apps (Grafana App SDK)
Backend apps are built using the Grafana App SDK, a Kubernetes-inspired framework that provides schema-first development with CUE definitions. Each app is self-contained with its own versioning, APIs, and dependencies.
Key Apps:
-
Dashboard App (
apps/dashboard/) - Manages dashboard resources with multiple API versions (v0alpha1, v1beta1, v2alpha1, v2beta1). Handles dashboard migrations, schema versioning, and layout conversions. -
Alerting Apps (
apps/alerting/) - Comprises three sub-apps:rules/- Alert rule definitions and managementnotifications/- Notification routing and receiver configurationhistorian/- Alert state history tracking
-
Folder App (
apps/folder/) - Manages folder hierarchies and organization. -
IAM App (
apps/iam/) - Identity and access management, roles, and permissions. -
Provisioning App (
apps/provisioning/) - Handles resource provisioning from external sources (Git, APIs). -
Other Apps - Playlist, Plugins, Preferences, Quotas, Annotations, Correlations, Advisor, and more.
App Structure
Each app follows a consistent pattern:
apps/myapp/
├── kinds/ # CUE schema definitions
│ ├── manifest.cue # App manifest (versions, kinds, permissions)
│ └── myapp.cue # Kind definitions
├── pkg/
│ ├── apis/ # Generated Go/TypeScript types
│ └── app/ # App implementation (New() entry point)
├── Makefile # Code generation via App SDK
└── go.mod
Code Generation: Run make generate to create Go and TypeScript types from CUE definitions using the Grafana App SDK.
Frontend Feature Modules
Frontend features are organized in public/app/features/ with domain-specific modules:
Core Features: dashboard, dashboard-scene, alerting, explore, datasources, plugins, connections
Management: admin, users, teams, org, profile, serviceaccounts
Data & Visualization: panel, visualization, transformers, expressions, annotations, variables, templating
Advanced: provisioning, correlations, library-panels, scopes, search, browse-dashboards
Each feature module contains components, state management (Redux/RTK Query), hooks, and utilities organized by responsibility.
App Registration
Apps are registered in pkg/registry/apps/ with installers that:
- Load the app manifest (schema definitions)
- Configure app-specific settings
- Register with the Grafana API server
- Enable feature-gated functionality
The ProvideAppInstallers() function in apps.go composes all active app installers based on feature flags and configuration.
Integration Pattern
Loading diagram...
Apps expose REST APIs that frontend features consume via RTK Query or direct HTTP calls. This separation enables independent iteration on backend schemas and frontend UX.
Infrastructure & Utilities
Relevant Files
pkg/infra- Core infrastructure servicespkg/util- Utility functions and helperspkg/middleware- HTTP middleware and request handlingpkg/setting- Configuration managementpkg/storage- Data storage backendspkg/modules- Module lifecycle management
Grafana's infrastructure layer provides foundational services for logging, caching, database access, tracing, and HTTP handling. These components enable reliable operation at scale.
Core Infrastructure Services
Database Access (pkg/infra/db) provides a unified interface for database operations across SQLite, MySQL, and PostgreSQL. The DB interface abstracts transaction management, dialect handling, and query execution through xorm.
Remote Caching (pkg/infra/remotecache) supports Redis, Memcached, and database-backed caching with optional encryption. Cache items are serialized using gob encoding, with configurable expiration and prefix support.
Logging (pkg/infra/log) uses structured logging with slog and go-kit/log. Loggers are organized hierarchically by name, support multiple handlers (file, syslog, console), and can be reloaded at runtime without restart.
Tracing (pkg/infra/tracing) integrates OpenTelemetry with support for Jaeger and OTLP exporters. Traces include service metadata, span attributes, and propagation across service boundaries for distributed tracing.
HTTP Client (pkg/infra/httpclient) provides a configurable HTTP client with middleware for authentication, metrics, response limits, and redirect handling. Supports datasource proxying with security validation.
Utilities and Helpers
Encoding & Encryption (pkg/util) includes password hashing (PBKDF2), AES encryption (CFB and GCM modes), base64 encoding, and random string generation for secure operations.
Validation (pkg/util/validation) provides email validation and other common checks. Input validation is performed at multiple layers for security.
Scheduling (pkg/util/scheduler) implements a worker pool pattern with configurable backoff and retry logic. Workers dequeue tasks and process them with exponential backoff on failure.
Debouncing (pkg/util/debouncer) groups rapid events by key and processes them after configurable wait periods. Useful for expensive operations triggered by frequent events.
Ring Data Structure (pkg/util/ring) provides a thread-safe circular buffer for efficient event queuing and adaptive channel sizing.
Middleware and Request Handling
HTTP Middleware (pkg/middleware) handles authentication, CSRF protection, security headers, compression, quota enforcement, and request tracing. Middleware is applied in a specific order to ensure proper request processing.
Security Headers include HSTS, X-Content-Type-Options, CSP, and X-Frame-Options. Headers are customizable per deployment and can be overridden for specific URLs like embedded dashboards.
Request Metadata captures trace IDs, user context, and organization information for logging and debugging. Contextual log providers allow injecting request-specific data into all log messages.
Configuration Management
Settings (pkg/setting) loads configuration from defaults.ini, environment variables, and command-line arguments. The Cfg struct centralizes all configuration with support for multiple database types, authentication methods, and feature flags.
Configuration is hierarchical: defaults are overridden by environment variables, which are overridden by command-line arguments. This allows flexible deployment across development, staging, and production environments.
Storage Backends
Unified Storage (pkg/storage/unified) provides a modern storage abstraction supporting Kubernetes-style resources. It can use SQL databases or gRPC-based remote storage, with automatic migrations from legacy tables.
Legacy SQL Storage (pkg/storage/legacysql) maintains compatibility with existing SQL-based storage for dashboards, folders, and other resources during migration periods.
Secret Storage (pkg/storage/secret) encrypts sensitive data at rest with configurable encryption backends and key rotation support.
Module System
Module Manager (pkg/modules) orchestrates service lifecycle using dskit's service framework. Modules are registered with dependencies, started in order, and stopped gracefully on shutdown. The system supports both visible and invisible modules for internal services.
Loading diagram...
Testing & Quality Assurance
Relevant Files
pkg/tests- Integration test infrastructuree2e- Cypress-based end-to-end testse2e-playwright- Playwright-based end-to-end testspackages/grafana-test-utils- Frontend testing utilitiescontribute/backend/recommended-practices.md- Backend testing guidelinescontribute/style-guides/testing.md- Frontend testing guidelinescontribute/style-guides/e2e-playwright.md- E2E testing framework
Grafana maintains a comprehensive testing strategy across backend, frontend, and end-to-end layers. The test suite ensures code quality, prevents regressions, and validates user workflows.
Backend Testing
Backend tests use Go's standard testing library with testify for assertions. Tests are organized into unit and integration categories.
Unit Tests: Run with make test-go-unit. Tests use the -short flag and timeout after 30 minutes. The test suite is sharded across multiple CI jobs for parallel execution.
Integration Tests: Run with make test-go-integration. These tests validate database interactions and external service integrations. Database-specific variants exist:
make test-go-integration-postgres- PostgreSQL backendmake test-go-integration-mysql- MySQL backendmake test-go-integration-redis- Redis cachemake test-go-integration-memcached- Memcached cache
The pkg/tests directory provides test infrastructure including the testsuite package for package-level setup and teardown, and testinfra utilities for database and service initialization.
Frontend Testing
Frontend tests use Jest with React Testing Library. Run all tests with make test-js or yarn test.
Best Practices:
- Use
*ByRolequeries to encourage accessibility-first testing - Use
user-eventlibrary instead offireEventfor realistic user interactions - Call
userEvent.setup()before tests to ensure proper async handling - Mock
getBackendSrv()andwindowobject using Jest spies
The packages/grafana-test-utils package provides shared testing utilities, fixtures, and mock handlers for consistent test setup across the codebase.
End-to-End Testing
Grafana uses Playwright for E2E tests, organized by feature area in e2e-playwright/. The framework follows the Page Object pattern with abstractions for Selectors, Pages, Components, and Flows.
Running Tests:
yarn e2e:playwright # Run all tests
yarn e2e:playwright --ui # Open interactive UI
yarn e2e:playwright --grep <testname> # Run specific test
yarn e2e:playwright --project <name> # Run entire project
Tests use data-testid attributes for element selection rather than CSS classes, ensuring stability across style changes. Tests run with 2 retries on CI and capture screenshots and traces on failure.
Quality Assurance
Code quality is enforced through linting and static analysis. Run make lint-go for backend linting with GolangCI-Lint. Frontend linting is integrated into the build process.
CI/CD pipelines run all test suites on pull requests. Backend tests are sharded across 16 parallel jobs for efficiency. Integration tests run against multiple database backends to ensure compatibility.
Loading diagram...
Development Workflow & Build System
Relevant Files
Makefile- Main build orchestrationbuild.go- Build entry pointpkg/build- Build system implementationcontribute/developer-guide.md- Developer setup guidecontribute/backend/manage-go-module.md- Go module managementdevenv- Development environment setuppackage.json- Frontend build scriptsgo.mod- Go dependencies
Grafana uses a dual-stack build system supporting both Go (backend) and Node.js (frontend). The build process is orchestrated through a comprehensive Makefile that coordinates code generation, compilation, testing, and packaging.
Build Architecture
Loading diagram...
Core Build Commands
The Makefile provides high-level targets for common development tasks:
Dependencies:
make deps-go- Install backend dependenciesmake deps-js- Install frontend dependencies (via Yarn)make node_modules- Install Node modules with immutable lock file
Building:
make build- Build both backend and frontendmake build-backend- Build Go binaries onlymake build-js- Build frontend assets onlymake build-server- Build Grafana server binarymake build-cli- Build Grafana CLI tool
Development:
make run- Build backend and watch for changes (uses Air)make run-frontend- Watch and rebuild frontend assetsmake run-go- Run backend server immediately with profiling
Code Generation
Grafana uses multiple code generation tools:
- Wire - Dependency injection graph generation (
make gen-go) - CUE - Configuration and schema generation (
make gen-cue) - Swagger - API specification generation (
make swagger-gen) - Feature toggles - Feature flag code generation (
make gen-feature-toggles) - Protobuf - Protocol buffer compilation (
make protobuf)
Testing
Loading diagram...
Frontend: yarn test runs Jest with watch mode. Use yarn test:coverage for coverage reports.
Backend: make test-go-unit runs unit tests. Integration tests require Docker: make test-go-integration-postgres or make test-go-integration-mysql.
E2E: yarn e2e:playwright runs Playwright tests. Install browsers first: yarn playwright install chromium.
Development Environment Setup
The devenv directory provides Docker Compose configurations for local development:
make devenv sources=postgres,prometheus,loki
Available sources include databases (PostgreSQL, MySQL), monitoring tools (Prometheus, Loki), and other services. Run ./devenv/setup.sh to provision default dashboards and data sources.
Go Module Management
Grafana uses Go workspaces for managing multiple modules. When creating new modules:
- Initialize the module in
pkg/your/module - Run
make update-workspaceto sync workspace files - Add module to
Dockerfileand.github/dependabot.yml - Use replace directives temporarily until merged to main
Docker Builds
make build-docker-full- Build development Docker imagemake build-docker-full-ubuntu- Build Ubuntu-based image
Both support environment variables for customizing Node and Go build modes.
Linting & Formatting
make lint-go- Run golangci-lint on backendmake gofmt- Format all Go filesmake shellcheck- Check shell scriptsyarn lint- Lint TypeScript and SASS
Key Build Flags
Go builds support several flags via environment variables:
GO_BUILD_DEV=dev- Development modeGO_BUILD_TAGS- Custom build tagsGO_RACE=1- Enable race detectorGO_BUILD_CGO- Control CGO compilation
Frontend builds use NODE_ENV (production/dev) and support feature toggles through environment variables.