Skip to main content

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

TagWhat it pinsUse it when
latestMost 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.
devNewest commit on main.Testing a change that hasn't been released. Accept churn.
sha-abc1234One exact dev build.Rollback or pinned dev testing.
X.Y.Z-abc1234Dev 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:

BumpWhat 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 /data was 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:

  1. The destructive migration runs.
  2. Your library files on disk are untouched — only DB rows are rebuilt.
  3. You'll need to rescan from Operations → Library scan → Run.
  4. The marker prevents the gate from reappearing on subsequent boots.
caution

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:

  1. Stop the container.
    docker compose down
  2. Restore /data from the snapshot you took before the upgrade (you took one, right?).
  3. Pin the previous version.
    image: ghcr.io/pauljoda/obscura:0.20.0 # or whatever the previous version was
  4. 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_dump of the embedded Postgres (more involved; you have to docker exec into the running container). Useful if you want a portable SQL dump independent of disk-format.
  • Just back up /data with rsync or restic. 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:

  1. A dev build 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 /data snapshot.
  2. 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."