Upgrades and backups
Upgrade a self-hosted SpecsGraph install with Docker Compose, pin image versions, back up Postgres with pg_dump, restore with psql and know what else to keep.
Pin versions and read release notes
The compose file tags every SpecsGraph image with ${SPECSGRAPH_VERSION}, set in .env. Pin it to a release such as 1.0.0 and never use latest: with a moving tag, any docker compose pull can upgrade you without notice, and the web, API and MCP services could end up on different versions.
Before each upgrade, read the notes for every release between your version and the target on the releases page (opens in a new tab). They list new settings, changed defaults and any step you must take by hand. Watch the repository for releases on GitHub so security fixes reach you quickly.
To see which version an install runs, list the images of its services. The tag after the image name is the version, the same value as SPECSGRAPH_VERSION:
docker compose images web api mcpUpgrade an install
Back up the database
Take a fresh backup as shown below. It is your way back if the upgrade goes wrong.
Shell mkdir -p backups docker compose exec -T postgres pg_dump -U specsgraph -d specsgraph | gzip > backups/specsgraph-pre-1.1.0.sql.gzChange the version
Set
SPECSGRAPH_VERSIONin.envto the new release.Shell sed -i 's/^SPECSGRAPH_VERSION=.*/SPECSGRAPH_VERSION=1.1.0/' .envPull and restart
Pull the new images, then let Compose recreate the services that changed.
Shell docker compose pull docker compose up -dWatch the start
Follow the logs until the
apiservice has applied its migrations and all three services are serving again. Then sign in and open a project to confirm.Shell docker compose logs -f web api mcp
Database migrations
Schema changes ship inside the images. The api service applies pending migrations when it starts, so there is no separate migration command. If the release notes name a version you must pass through, upgrade to that version first, let it start, then continue.
Roll back
Starting an older image does not undo migrations. To roll back, set SPECSGRAPH_VERSION to the previous version and restore the backup you took before the upgrade, following the restore steps below.
Postgres and Redis images
postgres:16 follows 16.x releases and redis:7 follows 7.x, so docker compose pull brings in their updates within that major version. A new major Postgres version is different: its data directory format changes, so you move with a dump and restore into a fresh volume, not by changing the tag.
Back up Postgres
Postgres holds everything that is not yet in Git and everything that never goes there: the graph, open proposals, review threads, members and personal access token records. Back it up with pg_dump, which works while SpecsGraph is running.
Take a backup
cd /opt/specsgraph
mkdir -p backups
docker compose exec -T postgres pg_dump -U specsgraph -d specsgraph | gzip > backups/specsgraph-$(date +%F).sql.gzSchedule backups
Run the backup every night from cron and copy the files off the server, for example to object storage in another location. A backup on the same disk does not survive the loss of that disk. In a crontab, % must be escaped:
15 2 * * * cd /opt/specsgraph && docker compose exec -T postgres pg_dump -U specsgraph -d specsgraph | gzip > backups/specsgraph-$(date +\%F).sql.gzRestore a backup
Stop the SpecsGraph services, recreate the database, load the dump with psql, then start the services again. The restore replaces everything in the database.
docker compose stop web api mcp
docker compose exec -T postgres dropdb -U specsgraph --if-exists specsgraph
docker compose exec -T postgres createdb -U specsgraph specsgraph
gunzip -c backups/specsgraph-2026-09-24.sql.gz \
| docker compose exec -T postgres psql -U specsgraph -d specsgraph -v ON_ERROR_STOP=1
docker compose start web api mcpTip
Test your restores
A backup you have never restored is a guess. Every few months, restore the latest dump into a scratch install and sign in to check it.
What else to back up
Store copies of .env and the key as carefully as the secrets they are. Redis holds only queues and caches, so it does not need backups. The caddy-data volume is optional too: Caddy requests new certificates if it is lost.
Your spec history is also in Git
Every published change is on your base branch, so the published spec and its full revision history survive even if the database does not. What Git does not hold is work in progress and workspace data: open proposals, review threads, members and personal access token records. Treat the repository as a second copy of the spec, not as a replacement for database backups.
Next steps
- History and versions: how revisions map to commits.
- Move between Cloud and self-hosted: how you will be able to hand operations to Cloud once it launches.
- Configuration reference: settings you may need after an upgrade.