Skip to main content
Version: 1.0.8

Backup & Restore

A backup is a single portable .qbak archive bundling the two kinds of state that together make a working deployment. It is one file: nothing else has to travel with it.

What is in a backup​

KindContents
Database entitiesUsers, roles and permissions; connections; the namespace tree (nodes, tags, protocol bindings); alarm definitions; user-defined types; REST routes and API keys; MQTT publishers; the imported symbol library; the AI configuration (endpoints, vocabulary, tag relationships); and the project registry — each dumped as a JSON section
Gateway variables 1.0.8Every gateway variable for a full-instance backup; for a project backup, that project's own variables plus every global one
File treesPer-project artifacts: pipelines, views, scripts, named queries, playbooks, specialists and assets
File Manager and uploaded filesThe file list always travels. The bytes are opt-in — see Media. Changed in 1.0.6
Not in a backupWhere it lives
Tag historyQuestDB — back it up with your database procedures
The audit journalThe external audit database — deliberately separate
Execution and system logsDiagnostic data, not configuration
Live runtime valuesReconstructed on start
.envBack it up separately; it holds ENCRYPTION_KEY

Encryption and secrets​

This is the part to get right.

BackupContains connection secretsAnyone opening it sees
Passphrase-encryptedYes, protected by the encryptionNothing without the passphrase — an opaque blob
UnencryptedNoConfiguration, with credentials blank

An unencrypted backup deliberately omits secrets so an unprotected archive cannot leak plant access. An encrypted backup is sealed whole — no usernames, no password hashes, no configuration, no secrets are readable without the passphrase.

Choose deliberately

An unencrypted backup restores with blank credentials — every connection must be re-entered. That is the right trade for an archive you cannot fully protect, and the wrong one for disaster recovery. For DR, use a passphrase and store it in your secrets manager.

Media: the File Manager and uploaded files New in 1.0.6​

Two file stores sit outside the project trees — the File Manager library, and the uploads folder behind style backgrounds, widget assets and anything a script wrote. Both are unbounded: they hold videos and 3D models, and can be a hundred times the size of the configuration beside them. A nightly backup dragging 400 MB of video is a backup that stops being run.

So Include File Manager & uploaded files is a checkbox on the export, and it is off by default. What that flag decides is the content, not the record:

Off (default)On
The archive carries the file list and every reference to it.It carries the list and the bytes.
A view pointing at Manuals/P-101.pdf still points at it after the restore.The same, with the file already in place.
Copy the two storage folders across and everything reconnects, with nothing further to do.Nothing further to do.
Kilobytes.However large the two folders are.

The checkbox says what it will cost. New in 1.0.7 Its label carries the size of the two folders — Include File Manager & uploaded files — adds 362 MB (363 files) — measured from the folder listing before anything is downloaded. Until 1.0.7 the only way to learn the size was to tick the box and watch the download. A folder that cannot be measured is said in amber under the label, never counted as zero: "0 MB" and "I could not look" must not look the same, because only one of them means the backup will be small. A failed estimate never blocks the backup.

The list is kept even when the bytes are missing, and that is what makes the default safe. A view references a library file by its id; dropping the row would destroy the id, so an operator who later configured the storage folder and copied the library across would get nothing back, with no remedy short of restoring the whole archive again. Keeping the row makes the obvious repair work — record and file find each other the moment the content lands.

Back the media up with the tool that is good at media

Both folders are effectively immutable, which is exactly what rsync and an incremental file backup are good at and what a ZIP rebuilt from scratch every night is bad at. Tick the flag for a deliberate full disaster-recovery copy; leave it off for the nightly.

If the target has no storage folder configured — a fresh install restoring from the setup wizard, which is the ordinary case — the restore says so once, with the remedy (Settings → Storage, then copy the folder across or restore again), rather than once per file.

Archives taken before 1.0.6 do not contain File Manager content

The File Manager stopped being an internal catalogue and became an ordinary folder on the server before the backup learned about it, so an archive from an earlier build carried an empty set and said nothing — "0 files" being indistinguishable from an installation that never used the feature. If you are relying on a pre-1.0.6 archive for File Manager content, take a fresh one with the flag ticked, or copy the folder across by hand.

Portability​

Backups are portable across machines because secrets are re-keyed in transit:

  1. On export, each connection is decrypted with the source machine's key.
  2. On restore, it is re-encrypted under the target machine's key.

The archive therefore never carries machine-key-encrypted blobs, which is exactly why copying the configuration database between machines does not work but a backup does.

Moving between Linux, Windows and macOS New in 1.0.6​

The two ends do not have to agree about what a filename is. Linux stores almost any byte sequence; Windows refuses ? * < > " | outright, folds upper and lower case together, and silently drops a trailing dot. So an ordinary Linux instance could produce an archive a Windows instance could not write back — and the three silent cases were the dangerous ones, because a trailing dot, a case variant or two Unicode spellings of the same word collapse two files into one with no error at either end.

A backup now reports them, at three points:

WhereWhat happens
ExportWarns about every name that would not survive somewhere else. This is the only end where you can still rename the thing.
ImportPre-flights before a byte moves. A project, view, script or named-query name that cannot be written is refused, and the message names the files. An asset name is a warning: those trees already degrade by skipping one file, and trading a disaster-recovery restore for an image is the wrong way round.
CreationAn asset filename is repaired on upload — nothing refers to it. A view, script or named-query name is refused with the reason, because the name is a key and the repair is not reversible: Flow? and Flow* would both become Flow_.

The rules belong to the filesystem, not the operating system, so the target's behaviour is measured by writing to it rather than assumed from the platform — a FAT32 stick on Linux folds case, and a case-sensitive volume on macOS does not. The check fails open: a pre-flight whose only power is to refuse must never refuse because it could not measure.

Passphrases typed on different platforms

An accented passphrase typed on a Mac and on Windows produces two different byte sequences for the same word. Passphrases are now normalised before the key is derived, so the two open the same archive. Archives sealed by an earlier build still open — the original bytes are tried as a fallback.

Which builds can read an archive New in 1.0.4​

An archive is forward-compatible and backward-refused: it restores into the build that made it and into every later one, and a build that predates it will refuse rather than read it wrongly.

The refusal is measured from what the archive actually contains, not from the version that produced it. An estate that never touched a newer feature keeps producing archives an older build accepts — gating on the version number would refuse a 1.0.5 backup on a 1.0.4 gateway over a stylesheet fix, and a guard that refuses safe things is a guard people learn to override.

A refusal names the producing build, this build, and the part of the archive responsible:

This backup cannot be imported by this build.

Created by QUBIQ 1.0.5 on 2026-09-08 14:12 UTC
This installation QUBIQ 1.0.4

Importing it would silently drop settings this build does not recognise.
designer views use schema 3; this build understands 2

The things that can raise the floor, each only when the archive actually carries it:

Archive contentWhy an older build must refuse it
An account with a pending password resetIt would restore the account without the reset, and the temporary password would stay in place.
The AI configuration — endpoints, vocabulary, tag relationshipsIt would report success and silently drop all of it.
REST routes and API keys, the File Manager catalogue, MQTT publishers, expression tags, the UDT member mapEach was outside the archive until it was added; an older build drops them.
The File Manager library as a folder 1.0.6See below.
The imported symbol library 1.0.8It would restore the rest, report success, and every placed imported symbol would render as missing.
A tag with a percent storage deadband 1.0.8It would read the number as engineering units — a 2 % band on a 0–1000 bar tag becomes a 2 bar band — and thin history on a band nobody chose.
Designer views, pipelines or database sections in a newer schemaIt could not read them faithfully.

The File Manager library is the clearest case of why the floor exists at all. An older build does not know the prefix the library now travels under, so it would ignore those entries, restore everything else and report success over an empty File Manager. Silent and total. An installation with no library folder configured, or an empty one, keeps producing archives an older gateway restores.

Restoring a 1.0.8 backup into 1.0.7 or earlier

A 1.0.8 archive restores into 1.0.7 unless it carries an imported symbol or a tag whose storage deadband is set as a percent — then 1.0.7 refuses it, naming the reason ("a tag's storage deadband is a percent of its engineering range; this build would read that number as engineering units"). Not every new setting raises the floor: the minimum time between stored samples and a tag's interpolation type are dropped by an older build, which then stores more often or uses its default — it never misreads a value it keeps. Gateway variables travel in their own entry, which an older build simply does not read.

Views are the exception to "it restores". A Designer view saved by 1.0.8 is in a newer view schema than 1.0.7 understands. The archive is accepted, but 1.0.7 refuses to render each such view and quarantines it rather than drawing it wrongly. A downgrade restore is for getting the plant model and connections back, not the screens.

Two things follow:

  • An archive with no compatibility envelope is adopted, not refused. Every backup taken before this shipped restores exactly as it did.
  • The same rule covers view packs and namespace exports, each measured against its own contents.
How far back can I restore?

Every archive at or below this build's level, indefinitely. There is no lower bound and no expiry.

Taking a backup​

Settings → Backup & Restore, which has a tab per scope:

TabCovers
Full instanceEverything — connections, the namespace, alarms, users, and every project
ProjectOne project's resources and assets
ViewsIndividual Designer views

Give the backup a passphrase first if it is to carry connection secrets, decide whether to tick Include File Manager & uploaded files — off by default, and the difference between kilobytes and gigabytes (→ Media) — and click Start backup.

Backups and restores run on the server Changed in 1.0.8​

A backup or a restore is a background job on the server. Start one and keep working, or leave the page: the job carries on, and you are told when it finishes. Until 1.0.8 each was one long browser request — the page had to stay open while the server built or applied the archive, and navigating away threw the work away.

The tray. While a job runs, a Backups & restores panel sits in the corner of every Platform page — 1 in progress — you can keep working — with one row per job: what it is, the step it is on (and, for a backup, how much has been written), and an indeterminate bar. When a job finishes a notice says so: Download on a finished backup, View report on a finished restore, Details on a failure. Finished jobs stay in the tray until you dismiss them.

Recent backups & restores. The Full instance tab lists the last ten jobs, with the same actions plus Remove from the server.

One at a timeJobs run in order; a second one waits — Waiting for another backup job to finish. A backup taken during a restore would read a half-restored instance, and two restores corrupt each other.
CancelA queued job, or a running backup, can be cancelled. A running restore cannot: stopping it part-way would leave the instance between two states.
Finished archivesKept on the server for 7 days, the newest 10, under backups/ in the data directory, so you can download one again.
Across a restartJob records survive a restart. A job cut off by one is marked interrupted, never left "running".
PassphrasesHeld in memory for the job only; never written to a job record.
Who sees a jobWhoever started it, and anyone with Manage Backup & Restore. A project owner does not see or download an instance backup somebody else took.

Taking a backup holds no lock; the gateway keeps running normally while it builds.

ScopePermission
Export or restore a full instance backupManage Backup & Restore
Export or restore one projectManage Project
Import a project as a new projectCreate Project

Manage Backup & Restore is super-admin-only by default: a backup can move an entire configuration off the machine. The Backup & Restore card in Settings — all three tabs — is shown only to holders of Manage Backup & Restore.

Every export and restore is recorded in the audit journal.

When to take one​

  • Before every upgrade. Schema migrations are not reversible.
  • At each commissioning milestone, so there is a known-good point to return to.
  • Before any bulk operation — a large namespace import, a UDT sync across many instances, a bulk delete.
  • On a schedule, retained off the machine.

Restoring​

  1. Stop what you can safely stop — pipelines, ideally the whole gateway for a full restore.

  2. Choose the archive, supply its passphrase if it is encrypted, choose the conflict policy (On conflict), and click Restore. The upload shows a percentage and can be cancelled — keep the page open until it reaches 100 %. From then on the restore is a server job: you can leave the page, and the report appears in place, or from the tray, when it finishes.

  3. Verify connections: enable each one and check it reaches connected, and re-enter credentials if the backup was unencrypted.

    A restore puts things back as they were, including what was switched off: a disabled connection stays disabled, a disabled tag stays disabled, and a suspended user stays suspended. Changed in 1.0.4 Earlier builds turned all three back on.

  4. Verify the namespace: check binding statistics for unbound tags.

  5. Verify projects: open each and confirm views load.

  6. Start pipelines.

A restore takes effect without a restart Changed in 1.0.8​

What a restore brings back is live the moment it finishes — full-instance, project and view-pack restores alike, from Settings or from the first-run wizard. Before 1.0.8, moving a project between installations could leave production showing the pre-restore project until QUBIQ was restarted, and some of it even after. Now:

  • Running pipelines of the restored projects are restarted on their restored graph.
  • Open browsers drop their cached copy of a restored project — the Designer draft and the LiveView snapshot — and reload it if it is open. A view import does the same for the views it replaced.
  • Restored views always look newer than what a browser has cached, so an older archived view cannot be hidden behind a newer cached one through reloads.
  • Overwrite onto an existing project of the same name keeps every pipeline in that project. Before, the project took the target's identity while its pipelines kept the source's, so they belonged to no project.
  • The safety copy taken before a restore (<project>.pre-restore-*) is no longer listed as a second project, in search or anywhere else.
  • Search covers the restored views, scripts, playbooks and specialists at once.

How large an archive can be restored Changed in 1.0.7​

ArchiveRestore limit
UnencryptedUp to 4 GB, read from disk rather than held in memory
Passphrase-encrypted512 MB

Before 1.0.7 every restore was capped at 512 MB and read whole into memory, while export had no limit at all — so an instance could produce a nightly backup it was structurally unable to restore, and find that out on the one day it mattered. Media-inclusive archives made that easy to reach.

An encrypted archive keeps the lower limit because of how it is sealed: the encryption authenticates the whole file before any of it can be trusted, so it has to be decrypted in one piece. An encrypted archive over the limit is refused with the reason, rather than exhausting the gateway's memory. To restore one, export again without the media flag — the usual cause of the size — or, where secrets need not travel, without a passphrase.

The conflict policy​

This is the setting to get right. It decides what happens to what is already on the machine.

PolicyWhat it doesUse it for
OverwriteReplaces existing connections, namespace entries and project files whose identifiers match.A restore — putting a machine back the way it was.
MergeKeeps what is there and adds only what is new. Existing connections, folders and tags are matched by name or path, so nothing is duplicated.Bringing one machine's configuration onto another that already has its own.
AbortRefuses unless the instance is empty.A first restore onto a fresh install, when you want to be told rather than to find out.

Overwrite is the default, and it is the destructive one. Take a backup of the current state before restoring, even when you are confident — especially then.

The restore report Changed in 1.0.8​

Every restore — instance, project, import as new, or a job's View report — shows the same report:

  1. Headline numbers — up to four of projects, files, tags, variables, connections and users.
  2. Needs attention, when there is anything to do, with each item named, not just counted:
    • connections to re-link — project resources reference a connection by name, so a project restored onto a machine with no connection by that name lands with those references dangling, which shows as a broken binding rather than as a failed restore;
    • files not on this installation yet — File Manager or uploaded files that are catalogued but whose content was not in the backup; copy the storage folder across and they reconnect;
    • symbols not added to the library — importing to the symbol library needs Manage Symbol Library; until someone who has it imports them, their instances render as deleted;
    • any other warning the restore raised.
  3. Every count, grouped and collapsed — Configuration, Namespace & tags, Files & media, AI, Gateway variables (restored, and kept as they were), Other.

The header names the archive, its size, the conflict policy and when it finished.

Migrating to a new machine​

1. Take a passphrase-encrypted backup on the source
2. Install QUBIQ on the target
3. Restore the backup from the first-run wizard (or create an admin, then restore from Settings)
4. Point the historian at its QuestDB store (take ownership if the source is retired)
5. Configure the audit journal's storage connection
6. Check every connection reaches connected
7. Start pipelines, verify screens, then decommission the source

Restoring from the first-run wizard takes the accounts from the backup too — you sign in afterwards with an administrator from the archive.

Step 4 matters: the historian records physical ownership inside the QuestDB store, so a restored configuration will refuse to write to a store the old machine still claims. Confirm the source is truly retired before taking ownership.

→ Store ownership

Project backups​

A project backup carries one project's resources and assets, not the instance's connections or namespace. Use it to promote an application between environments.

Settings → Backup & Restore → Project: pick a project, then one of three actions. Each runs as a server job.

ActionDoes
Back up projectWrites the chosen project as a .qbak — Start backup, then Download when it is ready.
Restore project…Puts a project archive back in place, under its original slug.
Import as new…Creates a copy under a New project name — the way to clone a project, or to bring a second copy of one onto a machine that already has it.

A project backup carries that project's own gateway variables and every global one. 1.0.8 Restoring it writes them back under the conflict policy: Overwrite replaces matching variables, Merge adds only those that are missing.

The prerequisite for all three is that the target already has connections and tags with the same names — project resources reference them by name, not by internal identifier. A restore says so in its report when they are missing.

For the plant model itself, use namespace export/import.

Disaster recovery​

A recoverable QUBIQ deployment needs six things, and losing any one leaves you rebuilding:

ItemStore where
Passphrase-encrypted configuration backupOff-machine backup storage
The File Manager and uploads folders — in the archive with the media flag ticked, or copied by your file-backup toolOff-machine, alongside the archive
.env (or at least ENCRYPTION_KEY)Secrets manager, separate from the backup
The database recovery keyOn paper, off the machine
QuestDB backupYour database backup procedures
Audit database backupIts own procedures, under separate administration

Test the restore. A backup that has never been restored is a hypothesis, not a plan. Restore into a scratch machine at least once per commissioning cycle.

Next​

→ Logs & diagnostics