Upgrades
How to upgrade a self-hosted Compass install: normal image updates and the one-time sub-calendar v1 cutover.
Back up first, every time. See Back up & restore
— ./compass update and ./compass rebuild don't snapshot your data or your
old app version, so a bad upgrade has no automatic rollback otherwise.
Normal upgrades (published images)
Most upgrades are a pull-and-restart of the published DockerHub images:
cd ~/compass
./compass update
This runs docker compose pull then docker compose up -d and waits for
the backend health check. It does not touch your data volumes — it only
replaces the running containers with newer images at whatever version
compass.yaml points at.
Upgrades from your own source checkout
If you run custom code — your own fork, or values baked into the web bundle at build time — update your git checkout and rebuild locally instead of pulling published images:
git pull
cd ~/compass
./compass rebuild
./compass rebuild builds images locally with Docker instead of pulling
them. It requires the build blocks in compose.yaml to be uncommented and
the full repo checkout present alongside it — see the Custom code
guide. It restarts and health-checks the same way
update does.
Mongo client options
Backend and Sync open their Mongo clients with wire compression (zstd, then
snappy, when that addon is installed), a warm pool (minPoolSize 2), and
maxIdleTimeMS of 60 seconds. Applying these options is not a data migration
and does not change indexes. A normal upgrade restart picks up the new
handshake.
A Mongo tier change is separate. Restart both the backend and the Sync process after the tier change so both clients reconnect.
Database migrations
Current releases do not ship a server-side migration runner or pending database migrations. Normal upgrades only replace the running images. Back up before an upgrade as usual; a future data repair will ship with its own operator runbook rather than silently running during deployment.
Duplicate local calendars (calendar_userId_local_unique)
The backend creates two indexes on the calendar collection at startup: one
on userId (for listing a user's calendars) and a unique partial index named
calendar_userId_local_unique so each user has at most one local calendar.
If your database already has two or more local calendars for the same user,
startup logs a warning, skips that unique index, and keeps running. The
userId index is still created. Until you dedupe, the unique guard the
backend assumes for ensureLocalCalendar is not in place.
To create the unique index:
-
Back up first (Back up & restore).
-
Connect
mongoshusing the API URI inmongo.uri(self-hosted default database:prod_calendar). The collection iscalendar. -
List users with more than one local calendar:
db.calendar.aggregate([{ $match: { "source.provider": "local" } },{$group: {_id: "$userId",count: { $sum: 1 },ids: { $push: "$_id" },},},{ $match: { count: { $gt: 1 } } },]); -
Keep one local calendar per user. Prefer the
_idthat user's events already reference (event.calendarId). Delete the extra local calendar rows. -
Restart the backend. The unique index is created on the next startup once no duplicates remain. Look for
Ensured calendar indexesin the backend log, and confirm the warning aboutcalendar_userId_local_uniqueis gone.
Upgrading from a pre-cutover install (before v1.0.236)
The sub-calendar v1 release (2026-07) moved events out of the legacy event
collection into a calendar-owned schema behind a one-time collection rename.
The migration code for that cutover shipped in releases up to v1.0.310
and was removed afterwards, so releases newer than v1.0.310 cannot migrate a
pre-cutover database.
If your install has never performed the cutover, upgrade in two steps:
- Upgrade to v1.0.310 and complete the cutover following that version's event migration runbook.
- Then upgrade to the latest release as a normal upgrade.
Installs that already cut over (or were first installed after v1.0.236) upgrade normally and can ignore this section.
What to read next
Server hosting guide (initial setup), Monitoring (what to watch after an upgrade), and Google Calendar (if the upgrade touches Google sync configuration).
Have an idea on how we can make self-hosting easier? Let us know in this GitHub Discussion.