Docker with PostgreSQL
By default, club uses SQLite for metadata storage. This guide covers switching to PostgreSQL for deployments that need more concurrency or robustness.
When to Use PostgreSQL
Stick with SQLite when:
- You have a small team (fewer than ~50 developers)
- You host fewer than ~10,000 packages
- You run a single club instance
- You want the simplest possible setup
Switch to PostgreSQL when:
- You have many concurrent users publishing or fetching packages
- You experience SQLite “database locked” errors under load
- You want to use your existing PostgreSQL infrastructure and backup tooling
- You plan to run multiple club instances behind a load balancer
- You need point-in-time recovery or streaming replication
docker-compose Override
club provides a compose override file that adds PostgreSQL alongside the main service. This layered approach keeps the base docker-compose.yml clean.
Create /opt/club/docker-compose.postgres.yml:
version: "3.9"
services: postgres: image: postgres:16-alpine container_name: club_postgres restart: unless-stopped environment: POSTGRES_DB: club POSTGRES_USER: club POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env} volumes: - club_postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U club"] interval: 10s timeout: 3s retries: 5
club: depends_on: postgres: condition: service_healthy environment: DB_BACKEND: postgres POSTGRES_URL: "postgres://club:${POSTGRES_PASSWORD}@postgres:5432/club"
volumes: club_postgres:.env additions
Add the PostgreSQL password to your existing .env file:
# Existing variablesSERVER_URL=https://packages.example.comJWT_SECRET=<your-jwt-secret>TRUST_PROXY=true
# PostgreSQLPOSTGRES_PASSWORD=<generate-a-strong-password>Generate a strong password:
echo "POSTGRES_PASSWORD=$(openssl rand -base64 24)" >> .envStarting with the override
Use both compose files together:
docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -dPostgreSQL Configuration
Connection URL format
The POSTGRES_URL environment variable follows standard PostgreSQL connection string format:
postgres://user:password@host:port/databaseExamples:
# Local Docker network (compose service name as hostname)POSTGRES_URL=postgres://club:secret@postgres:5432/club
# External PostgreSQL serverPOSTGRES_URL=postgres://club:secret@db.example.com:5432/club
# With SSLPOSTGRES_URL=postgres://club:secret@db.example.com:5432/club?sslmode=requireUsing an external PostgreSQL server
If you already have a PostgreSQL server (e.g., AWS RDS, Cloud SQL, or a shared instance), you do not need the postgres service in your compose file. Set the connection URL directly:
DB_BACKEND=postgresPOSTGRES_URL=postgres://club:secret@your-db-host.example.com:5432/clubAnd in docker-compose.yml, add the environment variables:
services: club: # ... existing configuration ... environment: DB_BACKEND: postgres POSTGRES_URL: ${POSTGRES_URL}PostgreSQL tuning
For a dedicated club PostgreSQL instance, these settings work well in postgresql.conf or as Docker environment variables:
postgres: image: postgres:16-alpine environment: POSTGRES_DB: club POSTGRES_USER: club POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} command: - "postgres" - "-c" - "shared_buffers=256MB" - "-c" - "effective_cache_size=512MB" - "-c" - "work_mem=4MB" - "-c" - "max_connections=50"Backing up PostgreSQL
# Dump the databasedocker exec club_postgres pg_dump -U club club > club-backup-$(date +%Y%m%d).sql
# Restoredocker exec -i club_postgres psql -U club club < club-backup.sqlMigration from SQLite to PostgreSQL
Option A: Start fresh (recommended for new instances)
If you have not published any packages yet, or if you can republish them:
- Stop club
- Switch the
.envto PostgreSQL (addDB_BACKEND=postgresandPOSTGRES_URL) - Start club with the postgres override
- club creates the schema automatically on startup
- Republish your packages
Option B: Export and reimport (for existing data)
-
Back up your SQLite database:
Terminal window docker exec club sqlite3 /data/club.db ".backup /tmp/club-backup.db"docker cp club:/tmp/club-backup.db ./club-backup.db -
Start PostgreSQL alongside club:
Terminal window docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -d -
Export data from SQLite and import into PostgreSQL using a tool like pgloader or a custom script. The table schemas are identical between backends.
-
Verify the data by checking the web UI and running a
dart pub getagainst a known package.
Full docker-compose Example
Here is a complete single-file compose configuration with PostgreSQL, for reference:
version: "3.9"
services: club: image: ghcr.io/birjuvachhani/club:latest container_name: club restart: unless-stopped ports: - "127.0.0.1:8080:8080" environment: SERVER_URL: https://packages.example.com JWT_SECRET: ${JWT_SECRET} TRUST_PROXY: "true" DB_BACKEND: postgres POSTGRES_URL: postgres://club:${POSTGRES_PASSWORD}@postgres:5432/club volumes: - club_data:/data depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s
postgres: image: postgres:16-alpine container_name: club_postgres restart: unless-stopped environment: POSTGRES_DB: club POSTGRES_USER: club POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - club_postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U club"] interval: 10s timeout: 3s retries: 5
volumes: club_data: club_postgres: