Skip to main content

Database architecture

Grafana’s database layer provides persistence for dashboards, users, organizations, data sources, and other core entities. The architecture supports multiple database backends with a unified abstraction layer.

Supported databases

Grafana supports three database backends:

SQLite (default)

  • Use case: Single-server deployments, development, testing
  • Location: <data>/grafana.db
  • Pros: Zero configuration, embedded, fast for small deployments
  • Cons: Not suitable for high-availability or distributed setups
  • Use case: Production deployments, high availability
  • Pros: ACID compliance, excellent performance, JSON support, full-text search
  • Cons: Requires separate database server

MySQL/MariaDB

  • Use case: Production deployments (alternative to PostgreSQL)
  • Pros: Widely used, good performance
  • Cons: Requires separate database server

Database abstraction layer

SQLStore

The main database interface is pkg/services/sqlstore/sqlstore.go:
Key methods:
  • WithDbSession - Execute queries in a session (no transaction)
  • WithTransactionalDbSession - Execute queries in a transaction
  • GetEngine - Get underlying XORM engine
  • GetDialect - Get database dialect for SQL differences

XORM engine

Grafana uses XORM as its ORM:

Session and transaction patterns

Non-transactional query

Transactional operations

Database schema

Core tables

Example schema: Dashboard table

Migration system

Database schema changes are managed through migrations in pkg/services/sqlstore/migrations/.

Migration structure

Running migrations

Migrations run automatically on server startup:
The migration system:
  • Tracks which migrations have run in the migration_log table
  • Executes only new migrations
  • Supports database-specific SQL via dialects
  • Can lock during migrations for multi-instance safety

Creating a new migration

  1. Add migration to appropriate file in pkg/services/sqlstore/migrations/:
  1. Register in migration initialization
  2. Test with all supported databases:

Repository pattern

Data access is organized using the repository pattern:
Benefits:
  • Abstraction from SQL details
  • Testability via mocks
  • Clear separation of concerns
  • Database-agnostic service layer

Raw SQL for complex queries

For complex queries, use raw SQL with proper escaping:

Database dialect handling

Handle database-specific differences:

Performance considerations

Indexes

Add indexes for frequently queried columns:

Query optimization

  • Use appropriate indexes
  • Avoid N+1 queries (use joins or batch loading)
  • Use pagination for large result sets
  • Cache frequently accessed data

Connection pooling

Configure connection pool in grafana.ini:

Unified Storage (experimental)

Grafana is moving towards Unified Storage backed by Kubernetes:
  • Location: pkg/storage/unified/
  • Purpose: K8s-native resource storage
  • Benefits: Scalability, consistency, versioning
  • Status: Experimental, opt-in via feature toggle
See pkg/storage/unified/migrations/ for migration path from SQL to Unified Storage.

Testing with databases

Unit tests with SQLite

Integration tests with PostgreSQL/MySQL

Key patterns summary

  • SQLStore abstraction - Unified interface for all databases
  • XORM ORM - Object-relational mapping
  • Migration system - Version-controlled schema changes
  • Repository pattern - Clean data access layer
  • Transaction support - ACID guarantees
  • Dialect handling - Database-specific SQL
  • Connection pooling - Performance optimization