Docs/ Operations

Database and backup

The default SQLite database is sufficient for most deployments. This page explains when to switch and how to create a backup that can actually be restored.

Which one should be used §

All three drivers are equally supported with the same features; their operational tradeoffs differ:

Driver Suitable for Cost
SQLiteDefault, no need to install anything. The recommended choice for a single-machine deployment. Data is in local files, moves with the machine
MySQL Existing MySQL operations and maintenance system, wanting unified backup and monitoring One more service to maintain
PostgreSQL Same as above, preferred PG ecosystem Same as above
No need to switch for performance

2.0 is designed for a single-instance deployment. An external database does not provide horizontal scalability and the database is rarely the performance bottleneck. Switch primarily to align operations, such as using an existing corporate backup process.

DSN syntax §

DATABASE_DSN selects the database. Leave it blank to use managed SQLite at DATA_DIR/gpt-load.db.

Three kinds of driver DSN
 # Leave blank: managed SQLite (default) 
DATABASE_DSN=

 # External SQLite: specify the file path 
DATABASE_DSN=sqlite:///var/lib/gpt-load/data.db

# MySQL
DATABASE_DSN=mysql://user:password@db.example:3306/gpt_load

# PostgreSQL
DATABASE_DSN=postgres://user:password@db.example:5432/gpt_load

Append driver-specific connection options in the query string:

With parameters
 # MySQL uses TLS 
mysql://user:pass@db.example:3306/gpt_load?tls=true

 # PostgreSQL requires SSL 
postgres://user:pass@db.example:5432/gpt_load?sslmode=require
Any non-empty DSN is considered self-managed

When DATABASE_DSN is non-empty, the gateway no longer takes over the directory and file permissions of this database, even if an external SQLite path equals the default location. You are responsible for permissions, backups, and disk management.

Connection-pool size is configurable; see Environment variables.

Schema migrations §

When an upgrade changes the schema, migration completes automatically at startup; no manual commands are needed. All three drivers use the same ordered migration chain, skipping completed migrations and applying the rest in sequence.

Backup before upgrading

Migrations are one-way: an older release may not understand schema changes applied by a newer one. Back up before every version upgrade so rollback remains possible.

If a migration is interrupted in an unsafe state, the program will refuse to start and report why instead of running on a damaged schema. Restoring a backup is then the fastest recovery path.

Backup §

Only backing up the database is not enough

The database must be paired with an encryption key from the same instance. When using auto-generated keys, auth.key and encryption.key are both stored in the data directory. If they are explicitly set through environment variables or a secrets manager, back them up separately from the original secure source. This release does not support master-key rotation.

SQLite (default official Compose setup) — stop the service first, resolve the actual volume name from the existing container, and archive the entire data directory. Run the following commands from the directory containing docker-compose.yml:

Back up the actual Compose data volume while stopped
docker compose stop gpt-load
container_id=$(docker compose ps -a -q gpt-load)
test -n "$container_id"
data_volume=$(docker inspect --format '{{range .Mounts}}{{if eq .Destination "/app/data"}}{{.Name}}{{end}}{{end}}' "$container_id")
test -n "$data_volume"
docker volume inspect "$data_volume" >/dev/null
backup_file="gpt-load-$(date +%F-%H%M%S).tar.gz"
docker run --rm --user 0:0 \
  --mount "type=volume,src=$data_volume,dst=/data,readonly" \
  --mount "type=bind,src=$PWD,dst=/backup" \
  alpine:3.24.1 sh -eu -c \
  'test -s /data/gpt-load.db; cd /data; tar -czf "/backup/$1" .' sh "$backup_file"
tar -tzf "$backup_file" | sed -n '1,20p'
docker compose start gpt-load

docker volume inspect and test -s must both succeed, and the archive listing must contain gpt-load.db. Do not pass the Compose logical volume name gpt-load-data directly to docker run -v—the actual volume name changes with the Compose project name.

External database — use the database's native backup tool, and back up the matching AUTH_KEY and ENCRYPTION_KEY from the current instance's secure source:

Use the database's native backup tool
mysqldump -h db.example -u user -p gpt_load > gpt_load.sql
 # Or 
pg_dump -h db.example -U user gpt_load > gpt_load.sql

Backup files contain decryptable credentials. Treat them as sensitive data: store them encrypted and never place them in public cloud storage or repositories.

Restore §

The key to recovery is that the database, encryption key, and application version must match. Do not overwrite a directory or volume that already contains data with the backup.

  1. Stop the target service and first back up its current data
  2. Verify the archive, then restore it into a new empty directory or volume
  3. Restore the ENCRYPTION_KEY that matches the database; restore explicitly configured keys from their original secure source
  4. For the first startup, use the same GPT-Load version as the backup; do not upgrade at the same time
  5. Check health, then sign in to the management UI and confirm that channel credentials decrypt correctly

A backup is valid only after you have verified that it can be restored. Test the process in a non-production environment before an incident reveals an incomplete backup.

Changing database drivers §

There is no automatic data migration tool. Changing drivers means using a new database and re-entering the configuration.

For a large configuration, run in parallel for a period of time: start a new instance on the new database, configure and validate it, then switch traffic. This is the same approach as Moving from 1.x.

After changing drivers, keep encryption.key unchanged. Keep the existing key so re-entered credentials use the same encryption as prior backups. A new key is valid only for a completely new setup, and its backup must be updated.

Database and backup - GPT-Load