Upgrades
Northplane is one binary (or one container image) with the UI, the docs and the schema migrations embedded. Upgrading means replacing that artefact and restarting; migrations run automatically on the first start. The steps differ slightly per deployment variant.
Before you upgrade
Section titled “Before you upgrade”- Back up: run
northplaned backup(or snapshot the data volume) and make suresecret.keyandconfig.yamlare safe — see Storage → Backup. Schema migrations are forward-only; the backup is your rollback path for data. - Note the running version (
GET /api/v1/system/infoor Admin → System health) so you can roll back to exactly that artefact. - Read the release notes of the target version (GitHub Releases for tagged versions; commit history for
main-<sha>images). - Plan a short outage: a restart takes seconds, migrations on the shipped schema take well under a minute, but active checks, SSE clients and agents reconnect afterwards (agents retry pushes; scheduled checks resume from the catalog).
How versions are identified
Section titled “How versions are identified”| Where | What you see |
|---|---|
northplaned version |
northplaned <version> (also in the help header) |
GET /api/v1/system/info (anonymous) |
"version":"…" together with goVersion, uptime, storage |
| Admin → System health (System-Health) | the system/info card |
| Login, setup and register pages | version in the footer |
GET /api/openapi.json / northplaned openapi |
info.version |
MCP (stdio and /mcp) |
server implementation version |
| Federation | each edge reports its version in the heartbeat; Admin → Sites (Standorte) shows it per site |
| Backup manifest | version field |
np --version |
np <version>; the usage text (np help) carries it too |
The string is injected at build time (-ldflags -X main.version=…): 1.0.0-dev for local builds, the git tag without the v for releases (1.2.0), main-<12-char sha> for images built from main, docker for an untagged local docker build.
Upgrade per variant
Section titled “Upgrade per variant”Single binary (systemd)
Section titled “Single binary (systemd)”-
Install the new binaries. Re-running the installer fetches the latest release and replaces
northplaned,npandnp-agentin place (install -m 0755), verifying the SHA-256 checksums:Terminal window curl -fsSL https://raw.githubusercontent.com/myfoxit/northplane/main/install.sh | shor download a specific
northplane_<tag>_<os>_<arch>.tar.gz+checksums.txtfrom the release page, verify, and copy the three binaries to/usr/local/bin. (NP_VERSION=vX.Y.Zpins the release — see Installation.) -
Optional pre-flight:
sudo -u northplane northplaned migrate -config /etc/northplane/config.yamlapplies pending migrations while the old service is still running and printsmigrations applied — schema is current. The old binary keeps working with the newer schema in the usual case (migrations are additive), so this shortens the restart window. -
systemctl restart northplaned, then watchjournalctl -u northplaned -fforstorage: applying migration …lines andnorthplane: listening. -
Upgrade agents on the hosts (
np-agentfrom the same tarball), then restart them (systemctl restart np-agent). Agents and server ship from the same release; the push/pull protocol is plain JSON over/api/v1/resultsand/api/v1/agent/checkswith no version handshake, so upgrading them in either order is fine (Agent).
Docker
Section titled “Docker”docker pull ghcr.io/myfoxit/northplane:latest # or a specific tagdocker stop northplane && docker rm northplanedocker run -d --name northplane -v northplane-data:/var/lib/northplane <the same ports, env and mounts as before> \ ghcr.io/myfoxit/northplane:latestState lives in the volume (/var/lib/northplane: core.db, event segments, tsdb/, and secret.key unless you mounted one), so recreating the container is safe.
Docker Compose
Section titled “Docker Compose”cd /opt/northplane # or wherever the stack livesdocker compose pulldocker compose up -ddocker compose logs -f northplane- The root
docker-compose.ymlreferencesghcr.io/myfoxit/northplane:latest;pullfetches whateverlatestis now. - The
deploy/stacks read the image fromNORTHPLANE_IMAGEin.env— pin it to an exact tag (ghcr.io/myfoxit/northplane:main-daa6dc518a2bor:1.2.0) and change that line to upgrade. Keep the previous value (the CI keeps it as.env.previous) for rollback. - Caddy is upgraded the same way (
caddy:2-alpine); certificates persist in thecaddy-datavolume.
Details of the stacks: Docker Compose deployment.
CI-driven production
Section titled “CI-driven production”On the reference production instance nothing is done by hand: a merge to main triggers CI, and a green CI run triggers the Deploy workflow, which builds and pushes ghcr.io/myfoxit/northplane:main-<sha> (+ latest), renders a fresh .env on the server (keeping the old one as .env.previous), runs docker compose pull && docker compose up -d --remove-orphans, and then verifies for up to 12 × 5 s that the container runs the wanted image and curl http://localhost:8443/healthz answers ok. If verification fails it restores .env.previous and brings the previous image back up — an automatic rollback. Manual runs (workflow_dispatch) can also flip demo mode. The whole chain, the GitHub variables/secrets and how to read a red run are documented in CI/CD; the current state of each environment is in Environments.
Tagged releases (v*) additionally produce the tarballs, the Windows zip (np/np-agent only) and semver image tags (Release process).
Schema migrations
Section titled “Schema migrations”- Migrations are applied automatically by the first command that opens the store after the upgrade — normally
serve— inside one transaction per migration, and logged asstorage: applying migration version=N name=….northplaned migratedoes the same without starting the server. - The migration list is embedded in the binary (9 migrations as of this version:
core,seed,user_roles,report_archive_slot,alert_ticket,hotpath_indices,user_tenant,ai_agent_chat,alert_snooze) and tracked in theschema_versiontable; see Storage → Schema migrations. - A failing migration stops the start (
northplaned: storage: migration N "name": …); the database is left at the last successfully committed migration. Fix the cause (disk, permissions, a PostgreSQL privilege) and start again. - Boot also reconciles built-in roles additively (for example the
operatorrole gainsalerts:writeif missing) and seeds the break-glass admin if no enabled local admin exists — both are idempotent and logged. - The NP-TSDB has no migration step; its block and aggregate files carry format headers (
NPBLOCK1,NPAGGR1) and are opened in place.
Rollback
Section titled “Rollback”Northplane has no down-migrations, so the cleanest rollback restores the pre-upgrade backup together with the previous artefact:
| Variant | Artefact rollback | Data rollback |
|---|---|---|
| Compose (deploy stacks) | mv .env.previous .env && docker compose up -d, or set NORTHPLANE_IMAGE back to the previous tag |
restore core.db, events-*.db, tsdb/ from the backup into the volume while the container is stopped (Restore) |
Compose (root stack, :latest) |
docker compose pull cannot go back by itself — set image: to an explicit older tag and up -d |
same |
| Docker | run the older tag | same |
| Single binary | reinstall the previous tarball’s binaries, systemctl restart northplaned |
restore the data directory from the backup |
| CI-driven | re-run the Deploy workflow for the previous green commit, or repoint NORTHPLANE_IMAGE on the server and up -d; the workflow rolls back automatically when verification fails |
restore the volume on the VM |
Because the migration runner only applies versions it knows and ignores higher ones, an older binary usually starts against a newer schema (the added columns/tables are simply unused). That is convenient for a quick revert after a bad deploy, but it is not a supported state to run in for long — restore the backup or move forward again.
Compatibility notes
Section titled “Compatibility notes”- UI and docs are embedded in the binary/image, so they are always exactly in sync with the API — there is nothing to clear or redeploy separately. Browsers pick up the new assets on reload (
/assets/*are content-hashed and cached immutably;index.htmlisno-cache). - API: all routes live under
/api/v1; responses are RFC 9457 problem documents; the OpenAPI document is generated from the route registry and the TypeScript client types are drift-checked in CI (make types-check), so the UI cannot silently lag behind the API. External clients should tolerate new fields in JSON responses. - Tokens, sessions, secrets survive upgrades; sessions are stored in the database, tokens are hashed rows, secrets are sealed with
secret.key. Never changesecret.keyas part of an upgrade. - Federation: main and edge instances are independent full installations; each reports its version in the heartbeat, and Admin → Sites shows it. Upgrade them independently; the pull/heartbeat protocol (
sites:pullwith ETag,sites:heartbeatJSON) has no version negotiation, so keep both on the same major version. - MCP clients connect with the same API tokens; tool lists may grow between versions.
- Event retention, TSDB retention and other constants may change between versions — re-read Configuration → Not configurable after major upgrades.
Verifying an upgrade
Section titled “Verifying an upgrade”curl -fsS https://<instance>/healthz→ok;curl -fsS https://<instance>/readyz→"ready":true.curl -fsS https://<instance>/api/v1/system/info→ the expectedversion.- Logs show the expected migration lines (or none) and no
background worker panickedmessages. - Log in, open Overview and Admin → System health; queue depths near zero,
scheduler.scheduledequals your object count. - Trigger a check (
np check-now <object-id>) and a test notification (POST /api/v1/channels/{name}:test-notification) to confirm the pipeline and the outbox. np audit verify→audit chain intact (N entries verified).- If you run agents or an edge, check Admin → Agents / Admin → Sites for fresh heartbeats.