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
PostgreSQL (recommended for production)
- 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 ispkg/services/sqlstore/sqlstore.go:
WithDbSession- Execute queries in a session (no transaction)WithTransactionalDbSession- Execute queries in a transactionGetEngine- Get underlying XORM engineGetDialect- 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
| Table | Purpose |
|---|---|
dashboard | Dashboard definitions and metadata |
dashboard_version | Dashboard version history |
folder | Folder hierarchy |
data_source | Data source configurations |
user | User accounts |
org | Organizations |
org_user | User-organization memberships |
team | Teams within organizations |
team_member | Team memberships |
playlist | Playlist definitions |
alert | Legacy alerting rules |
alert_rule | Unified alerting rules |
annotation | Dashboard annotations |
api_key | API keys for authentication |
session | User sessions |
Example schema: Dashboard table
Migration system
Database schema changes are managed through migrations inpkg/services/sqlstore/migrations/.
Migration structure
Running migrations
Migrations run automatically on server startup:- Tracks which migrations have run in the
migration_logtable - Executes only new migrations
- Supports database-specific SQL via dialects
- Can lock during migrations for multi-instance safety
Creating a new migration
- Add migration to appropriate file in
pkg/services/sqlstore/migrations/:
- Register in migration initialization
- Test with all supported databases:
Repository pattern
Data access is organized using the repository pattern:- 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 ingrafana.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
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