Automatic Updates
SeqDesk has a built-in updater in the admin panel. It stages each new release
into its own directory, activates it with an atomic current/ symlink swap, runs
migrations, and restarts — keeping the previous release intact for an instant
rollback.
Before you start
- You need the FACILITY_ADMIN role. Every update endpoint returns
401otherwise. - The install must be on PostgreSQL. Releases that declare a PostgreSQL requirement refuse to install on anything else.
- The server must be running Node.js 22.13.0 or newer on the 22.x line, or 24.x. Anything else is rejected before the download starts.
- Only one update, repair or rollback can run at a time.
- Updates restart the application. Schedule them when no pipeline run needs the web process — running Nextflow jobs are not killed, but the run monitor is offline while the app is down.
Where it lives
Sidebar Settings → Info (/admin/settings) opens the Platform Info page.
Scroll to the Software Updates panel. It shows three cards — Running,
Installed, Latest — and the actions described below.
Facility admins also see a dismissible update available banner at the top of the app, which links to the same panel.
Update flow
Check for updates
The panel checks the update server on load. Check now forces a fresh check:
GET /api/admin/updates?force=trueThe response carries:
| Field | Meaning |
|---|---|
runningVersion | The version of the process currently serving requests |
installedVersion | The version on disk in the active release |
restartRequired | true when the two differ — the update landed but the restart has not completed |
updateAvailable, latest | Whether a newer release exists, and its metadata |
currentDatabaseProvider | postgresql, sqlite, or unknown |
databaseCompatible, databaseCompatibilityError | The compatibility gate result |
Results are cached for 1 hour, keyed on the running version and the database provider. Any check that is not served from that cache — including a forced one — also sends an anonymous telemetry heartbeat (running and installed version, whether an update is available, the latest version, the database provider), if telemetry is enabled. See Operational Telemetry.
If the update server cannot be reached, the response carries an error string
and updateAvailable: false; the panel shows Update check failed and the
message. That is a check failure, not an install failure — nothing has changed.
Compatibility gate
Before anything is downloaded, the server verifies the release is compatible with
the configured database. A release marked databaseRequirement: "postgresql" on
a non-PostgreSQL install is rejected with HTTP 409 and never started. The
button reads Migration required and the panel explains that a manual database
migration is needed.
Disk space check
The updater requires at least 150 MB free on the install root. Below that it
fails immediately with Insufficient disk space: <free>MB free, 150MB required.
On platforms where free space cannot be measured, the check is skipped rather
than guessed.
Validate and download
The release is validated before a byte is fetched:
- the version string must match a conservative safe pattern;
- the running Node.js major must be supported, and at least the release’s
minNodeVersion; - the download URL must be
https.httpis rejected unlessSEQDESK_ALLOW_INSECURE_UPDATE=trueis set, which exists for an internal mirror on a trusted link; - the release metadata must carry a real
sha256:<hex>checksum. A missing checksum, or the literal placeholder, is refused.
The tarball is then downloaded from the configured update server (default
https://seqdesk.org, override with SEQDESK_UPDATE_SERVER) and its SHA-256 is
verified against the manifest.
Stage the release
The tarball is extracted into a staging directory, its version is verified
against what was advertised, and the shared config file is linked in. Production
dependencies are installed in the staged tree with
npm ci --omit=dev --no-audit --no-fund, and the Prisma client is generated
there too. The running application is untouched throughout.
Staging then asserts that node_modules/.bin/next and node_modules/.bin/prisma
both exist, so a silently incomplete install cannot be activated. On NFS, where
npm ci can fail trying to unlink a held Prisma client artefact, it retries once
with npm install --omit=dev.
Activate (atomic symlink swap)
Shared runtime paths (data/, pipelines/, pipeline_runs/, settings.json)
are linked into the staged release, the root start.sh wrapper is rewritten, the
staged tree is published as releases/<version>, and current/ is atomically
switched to point at it. The previously active release directory is left in place
for rollback.
Back up, then migrate
A best-effort pg_dump -Fc is written to
<root>/backups/pre-update-<timestamp>.dump. The connection string is passed
through the environment, never on the command line, so the password does not
appear in the process list. If pg_dump is unavailable the update continues
without a restore point.
Migrations then run from the newly activated release with
prisma migrate deploy (forward-only). Record counts for sequencing orders,
samples, studies and users are snapshotted before and after; if any count drops,
the update aborts, current/ is switched back to the previous release, and
the error names the dump to restore.
Restart
The updater tries, in order, pm2 restart seqdesk, a user systemd service
(systemctl --user restart seqdesk), and a system service
(sudo -n systemctl restart seqdesk — non-interactive, so it never hangs on a
password prompt). If none succeeds it exits non-zero so a supervisor configured
with Restart=on-failure relaunches it, after printing a message telling you to
restart manually if it does not come back.
Progress can be polled while all of this happens:
GET /api/admin/updates/progressSafeguards
| Safeguard | Behaviour |
|---|---|
| Role gate | Every update endpoint requires a FACILITY_ADMIN session; otherwise 401 |
| Database-compatibility gate | Install rejected with 409 if the release requires a backend the install does not have |
| Node.js version gate | Rejected before download if the running Node major is unsupported or older than the release’s minNodeVersion |
| Transport | https only, unless SEQDESK_ALLOW_INSECURE_UPDATE=true |
| Checksum verification | A missing, placeholder, malformed or mismatched SHA-256 aborts the install |
| Staged dependency install | npm ci runs in staging; next and prisma binaries are asserted before activation |
| Atomic activation | The current/ symlink swap means there is never a partially-overwritten install |
| Pre-migration dump | Best-effort pg_dump -Fc into <root>/backups/ |
| Data-loss abort | Update aborts and reverts the symlink if order/sample/study/user counts drop after migrations |
| Update lock | One update at a time; a second request gets 409 |
Update phases
The progress endpoint reports a coarse status and a percentage; a finer-grained
phase is written to .update-state.json at the install root.
status | Description |
|---|---|
checking | Preparing the update or verifying availability |
downloading | Disk-space check, download, checksum verification |
extracting | Staging, dependency install, activation, and migrations |
restarting | Application restart in progress |
complete | Update finished successfully |
error | Update failed — the message and error are shown in the panel |
phase in .update-state.json | Reached when |
|---|---|
preparing | The layout has been resolved and the previous release recorded |
staged | The tarball has been extracted into staging |
activating | Shared paths linked; about to publish and swap |
migrating | The new release is live; migrations are running |
complete | Update succeeded |
error | Update failed |
rollback_started, rolled_back | A rollback is in progress or finished |
Update lock
Only one update can run at a time. The updater writes .update-lock at the
install root before starting; a second install or rollback request while one is
in progress returns 409 Update already in progress.
The lock auto-expires after 1 hour so a crashed update cannot wedge the
system permanently, and it is refreshed on every progress report — so a
legitimately slow download or npm ci is not mistaken for a stale lock and
overwritten by a concurrent update.
The progress endpoint also self-heals: once the target version is both installed
on disk and running, it marks a stuck status as complete (or clears a stale
error) and releases the lock.
In-app notifications
Facility admins receive in-app notifications at three points only — when an
update or repair starts, when it completes, and when it fails. There
is no notification for intermediate progress; watch the panel or the progress
endpoint for that. Each notification links back to /admin/settings.
Recovery actions
When an update ends in error, the Software Updates panel offers three
buttons:
- Roll back release — one-click revert to the previous release
(
POST /api/admin/updates/rollback). Shown only when a previous release is recorded. See Manual Update & Rollback. - Retry update — repairs the active release in place
(
POST /api/admin/updates/installwith{ "repair": true }): reinstalls dependencies withnpm install --omit=dev, regenerates the Prisma client, takes another pre-migration dump, and re-runs migrations. It does not download anything. Use it when the release is correct but its dependency tree or Prisma client is broken. - Clear failed status — discards the stale error state and releases the lock
(
DELETE /api/admin/updates/progress). It refuses with 409 while an update is genuinely in progress.
Configuration
| Variable | Default | Description |
|---|---|---|
SEQDESK_UPDATE_SERVER | https://seqdesk.org | Update server URL; also settable as runtime.updateServer in settings.json |
SEQDESK_ALLOW_INSECURE_UPDATE | unset | true permits an http:// download URL |
Troubleshooting
“Update already in progress” but nothing is happening. The lock is stale.
Either wait for the 1-hour TTL, or use Clear failed status once the panel
shows error. If the status is not error, the endpoint refuses — check
.update-status.json at the install root to see what the last reported phase
was.
“Insufficient disk space: 40MB free, 150MB required”. Free space on the
filesystem holding the install root. Old releases/ directories are never pruned
automatically and are usually the largest thing there — see
Manual Update & Rollback.
“Unsupported download URL protocol: http:”. The release manifest points at a
plain-HTTP URL. That is only permitted with
SEQDESK_ALLOW_INSECURE_UPDATE=true, and only sensibly for an internal mirror.
“Release is missing a checksum” / “Checksum mismatch”. The download did not match the published SHA-256 or none was published. Do not work around this; retry the check, and if it persists, the release metadata or the mirror is wrong.
“SeqDesk … supports Node.js 22.13.0+ … but SeqDesk is running Node.js …”. Switch the service to a supported Node LTS, restart, then retry.
“Runtime dependency install did not create node_modules/.bin/next”. Staging
completed but produced an incomplete tree — usually a network failure mid-npm ci or an out-of-space condition. Free space, then retry.
“Aborting update: data loss detected after migrations”. The safety net fired.
The code symlink is already back on the previous release, but the database is
migrated and was not rolled back. Restore the dump named in the message with
pg_restore before retrying. Full procedure:
Manual Update & Rollback.
The panel says “Restart pending”. The new version is installed on disk but
the process is still the old one — the automatic restart did not take. Restart
your process manager: pm2 restart seqdesk, systemctl --user restart seqdesk,
or sudo systemctl restart seqdesk.
Anything else. Run seqdesk doctor to narrow the
failure to layout, database, or HTTP, then follow
Manual Update & Rollback.
The update, repair and rollback flow — including the data-loss abort — is covered by automated end-to-end tests that run before every release.