
Migrating Grafana from SQLite to PostgreSQL with Docker Compose

By default, Grafana ships with a lightweight SQLite database to store dashboards, users, and configuration. While SQLite works fine for small setups, it quickly becomes a bottleneck in production environments where reliability, performance, and scaling matter. PostgreSQL is a natural upgrade: it’s robust, battle-tested, and integrates well with Grafana.
In this post, I’ll walk you through migrating Grafana’s default SQLite backend to PostgreSQL using Docker Compose and pgloader.
Why Migrate to PostgreSQL?
- Scalability: PostgreSQL handles larger datasets and higher query loads better than SQLite.
- Reliability: Supports advanced features like replication, backups, and tuning.
- Ecosystem Integration: Unlike SQLite, which is just a local file, PostgreSQL runs as a proper database server.
Migration Steps
We’ll assume you’re already running Grafana with Docker Compose, using the default SQLite backend.
1. Stop the Grafana container
Before doing anything else, stop the Grafana service to prevent new writes during migration:
docker compose stop grafana
2. Backup the SQLite database
The SQLite database file is usually named grafana.db and lives inside Grafana’s storage directory (/var/lib/grafana/ by default). Copy it somewhere safe:
cp ./grafana/data/grafana.db ./grafana/data/grafana.db.bak
3. Add PostgreSQL to Docker Compose
Extend your docker-compose.yml to include a PostgreSQL service. Example:
services:
postgres:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_USER: grafana
POSTGRES_PASSWORD: grafana
POSTGRES_DB: grafana
volumes:
- ./postgres-data:/var/lib/postgresql/data
expose:
- "5432"
4. Configure Grafana to use PostgreSQL
Update your Grafana service configuration so it connects to PostgreSQL. You can either adjust environment variables in docker-compose.yml or mount a grafana.ini file. For environment variables:
services:
grafana:
image: grafana/grafana-oss
environment:
- GF_DATABASE_TYPE=postgres
- GF_DATABASE_HOST=postgres:5432
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=grafana
- GF_DATABASE_PASSWORD=grafana
volumes:
- "./data:/var/lib/grafana"
depends_on:
- postgres
5. Start PostgreSQL and initialize schema
Bring up the PostgreSQL container:
docker compose up -d postgres
Now start Grafana once so it automatically creates the schema in PostgreSQL:
docker compose up -d grafana
When Grafana has finished booting, stop it again:
docker compose stop grafana
6. Add pgloader to Docker Compose
pgloader makes it easy to migrate from SQLite to PostgreSQL. Add it to your docker-compose.yml:
pgloader:
image: ghcr.io/dimitri/pgloader:latest
container_name: pgloader
command: pgloader /grafana.load
restart: "no"
depends_on:
- postgres
volumes:
- "./data:/data"
- "./grafana.load:/grafana.load"
Create grafana.load file
load database
from sqlite:///data/grafana.db
into postgresql://grafana:grafana@grafana-postgres:5432/grafana
with data only, truncate, reset sequences;
7. Run pgloader
Run pgloader with options to only migrate data, ensuring sequences and constraints are reset properly:
docker compose up pgloader
This will transfer all existing dashboards, users, and config into the PostgreSQL database.
After pgloader was executed once you should comment it out in your docker compose file to avoid future overwrites of the postgresql database.
8. Start Grafana with PostgreSQL
Now start Grafana again:
docker compose up -d grafana
Grafana should now run using PostgreSQL as its backend — with all your existing data intact.
Verifying the Migration
Log into Grafana and confirm that:
- Your dashboards are still there
- Users are intact
If everything looks good, you can safely remove the old SQLite file backup later.
Full Example: docker-compose.yml
Here’s a working example you can adapt to your setup:
version: "3.9"
services:
grafana:
image: grafana/grafana-oss
container_name: grafana
restart: unless-stopped
environment:
- GF_DATABASE_TYPE=postgres
- GF_DATABASE_HOST=grafana-postgres:5432
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=grafana
- GF_DATABASE_PASSWORD=grafana
ports:
- "3000:3000"
volumes:
- "./data:/var/lib/grafana"
depends_on:
- postgres
postgres:
image: postgres:17-alpine
container_name: grafana-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=grafana
- POSTGRES_PASSWORD=grafana
- POSTGRES_DB=grafana
volumes:
- "./postgres-data-4:/var/lib/postgresql/data"
expose:
- "5432"
pgloader:
image: ghcr.io/dimitri/pgloader:latest
container_name: pgloader
command: pgloader /grafana.load
restart: "no"
depends_on:
- postgres
volumes:
- "./data:/data"
- "./grafana.load:/grafana.load"
Conclusion
Migrating Grafana from SQLite to PostgreSQL is straightforward with Docker Compose and pgloader. The key is to let Grafana generate the schema first, then import the data with pgloader’s data only option.
You now have a more robust Grafana backend that’s production-ready and easier to maintain at scale.
The migration steps are of course transferable to Kubernetes setups.