Upgrading
Obscura is pre-1.0 and we don't carry compatibility shims between schema breaks. This page tells you what each image tag means, how the breaking-gate works, and how to roll back when something doesn't go your way.
Image tags
| Tag | What it pins | Use it when |
|---|---|---|
latest | Most recent stable release. | Normal installs. Moves only when the Release workflow runs. |
X.Y.Z (e.g. 0.20.1) | One exact release. | Pin a known-good version. |
X.Y (e.g. 0.20) | Latest patch on a minor line. | Track bug fixes only. |
X (e.g. 0) | Latest minor on a major line. | Long-running deployment with the broadest tracking band. |
dev | Newest commit on main. | Testing a change that hasn't been released. Accept churn. |
sha-abc1234 | One exact dev build. | Rollback or pinned dev testing. |
X.Y.Z-abc1234 | Dev build labelled with the in-flight version marker. | Same as sha-, with the next-version cue baked in. |
latest always resolves to the most recent released version. dev is rebuilt on every push to main (excluding the release workflow's own commits). For the bleeding edge with rollback safety, pin to a specific sha-… tag and bump it deliberately.
Versioning policy
Obscura follows Semantic Versioning:
| Bump | What it means |
|---|---|
MAJOR (1.0.0) | Breaking API changes, schema changes that need manual migration, config-format changes. |
MINOR (0.21.0) | New features, new API endpoints, new UI views. |
PATCH (0.20.1) | Bug fixes, UI tweaks, dependency updates, docs. |
Between releases, package.json carries a pre-release marker — 0.21.0-dev means "the next release will be at least 0.21.0." This is what dev builds are tagged from.
Where to find the changelog
The release notes are in CHANGELOG.md and in the GitHub Releases page. Every release section starts with a What's New block written for users — read that before upgrading.
Routine upgrades
The happy path:
docker compose pull && docker compose up -d
Migrations apply on boot. The web UI and worker share the same migration runner; whichever process starts first runs the migrations and the other waits.
If a migration fails, the container exits — Obscura would rather refuse to start than serve a half-migrated database. The error appears in docker compose logs obscura.
Breaking upgrades and the gate
When a release would destroy data, Obscura blocks startup with a one-time gate before the destructive migration runs.
You'll see this if:
- Your
/datawas created on an older schema with data the new release intends to drop, and - You haven't already accepted this gate.
The gate explains what changes and what to do (almost always: "rescan your library after continuing"). Click Continue & rebuild library to accept; Obscura writes a marker at /data/.breaking-gate/<gate-id>.accepted, restarts the API process, and reloads the page when it comes back up.
After the gate accepts:
- The destructive migration runs.
- Your library files on disk are untouched — only DB rows are rebuilt.
- You'll need to rescan from Operations → Library scan → Run.
- The marker prevents the gate from reappearing on subsequent boots.
The gate is the only "are you sure" step. If you click through and decide later you wanted the old state, the only way back is restoring /data from a snapshot taken before the upgrade. Take the snapshot first.
The full policy lives in CLAUDE.md under "Breaking-change policy" and the implementation is at packages/db/src/breaking-gate.ts.
Rolling back
If a release is broken on your setup:
- Stop the container.
docker compose down
- Restore
/datafrom the snapshot you took before the upgrade (you took one, right?). - Pin the previous version.
image: ghcr.io/pauljoda/obscura:0.20.0 # or whatever the previous version was
- Bring it back up.
docker compose up -d
Without a /data snapshot, rollback after a forward-only migration isn't possible. Snapshot before any upgrade you can't easily redo.
Backups
Obscura ships no built-in backup tool. The strategies that work:
- Volume snapshot (ZFS, btrfs, LVM) of
/data. Cheap, instant, the safest option for downgrade. pg_dumpof the embedded Postgres (more involved; you have todocker execinto the running container). Useful if you want a portable SQL dump independent of disk-format.- Just back up
/datawithrsyncorrestic. Stop the container first to get a consistent snapshot — Postgres files are not safe to copy while it's running.
Your media (/media) doesn't need a backup from Obscura's perspective — it's read-only as far as Obscura is concerned and lives wherever you keep your files.
Dev image discipline
The dev tag exists for testing in-flight work. It is rebuilt on every push to main and may include schema changes that haven't shipped to a release. Two things to know:
- A
devbuild can advance the schema. If you go back to a release tag afterwards, the schema may be ahead of what that release knows how to talk to. Treat going back to release as a downgrade — restore a/datasnapshot. - The release workflow skips its own commits when picking dev builds (commits whose message starts with
chore(release):), so you won't get a dev build of the release commit.
In short: dev is fine for testing, not great for "I'll just leave this running and see how it goes."